{"_id":"@agglabs-one/pay","name":"@agglabs-one/pay","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agglabs-one/pay","version":"0.1.0","description":"Client SDK for AGG One Payments — signed integration API (customers, cards, invoices, subscriptions) and outbound webhook verification.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"engines":{"node":">=18"},"dependencies":{"@agglabs-one/core":"^0.1.0"},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"npm run build"},"keywords":["agglabs","agg-one","pay","payments","stripe","invoices","subscriptions","billing","webhooks","hmac"],"license":"UNLICENSED","publishConfig":{"access":"public"},"_id":"@agglabs-one/pay@0.1.0","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-GIP1jNB7huG+4h7ka0+DLOEZgpW72yIgTP9emsehnY+qgOSddge4pCCO2ZLbcnjmzWQg9gm1+Fzg5X8e86DGlA==","shasum":"338626ed2f3a0df6e3ae1315c94f4007260c5eef","tarball":"https://registry.npmjs.org/@agglabs-one/pay/-/pay-0.1.0.tgz","fileCount":18,"unpackedSize":53254,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFqxcj86qKrsCmOV2nzIbfUi3zQr62CG1Q0o8sYkyjndAiEAvi5SrsCXtO6XANtIR/iQSc2Kx9sUvmzh3bmein7GUJM="}]},"_npmUser":{"name":"agglabs","email":"maciejpukszta@agglabs.com"},"directories":{},"maintainers":[{"name":"agglabs","email":"maciejpukszta@agglabs.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pay_0.1.0_1786818922170_0.47962359581851177"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T18:35:21.959Z","0.1.0":"2026-08-15T18:35:22.285Z","modified":"2026-08-15T18:35:22.567Z"},"maintainers":[{"name":"agglabs","email":"maciejpukszta@agglabs.com"}],"description":"Client SDK for AGG One Payments — signed integration API (customers, cards, invoices, subscriptions) and outbound webhook verification.","keywords":["agglabs","agg-one","pay","payments","stripe","invoices","subscriptions","billing","webhooks","hmac"],"license":"UNLICENSED","readme":"# @agglabs-one/pay\n\nClient SDK for **AGG One Payments** (`pay.agglabs.com`). Signed integration API +\noutbound webhook verifier — one shared HMAC secret for both directions.\n\n```bash\nnpm install @agglabs-one/pay\n```\n\n## Quick start\n\n```ts\nimport { Pay } from '@agglabs-one/pay';\n\nconst pay = new Pay({\n  keyId:     process.env.PAYMENTS_KEY_ID!,      // ak_...\n  keySecret: process.env.PAYMENTS_KEY_SECRET!,\n  // baseUrl defaults to https://pay.agglabs.com\n});\n\n// 1) Make sure we have a customer for this workspace\nconst customer = await pay.customers.ensure({\n  appId: 'agg-one',\n  externalId: workspaceId,\n  email: user.email,\n  name: workspace.name,\n  currency: 'PLN',\n});\n\n// 2) Create a monthly subscription with a 7-day trial\nconst { subscribeUrl, payUrl } = await pay.subscriptions.create({\n  customerId:  customer.id,\n  currency:    'PLN',\n  description: 'Plan Pro',\n  unitAmount:  29.99,        // major units per period\n  interval:    'month',\n  trialDays:   7,\n  proration:   'create_prorations',\n});\n\n// Send `payUrl` to redirect straight to Stripe Checkout,\n// or `subscribeUrl` for the AGG-hosted status page.\n```\n\n## What's in the box\n\n| Namespace | Highlights |\n|---|---|\n| `pay.customers`      | `ensure`, `get`, `invoices`, `charge` (off-session) |\n| `pay.cards`          | `setupIntent`, `list`, `makeDefault`, `remove` |\n| `pay.invoices`       | `create`, `receipt`, `markPaid`, `isPaid` |\n| `pay.subscriptions`  | `create`, `get`, `getByToken`, `listByCustomer`, `cancel`, `resume`, `changePrice`, `periods` |\n| `pay.webhooks`       | `test`, `recent` (debugging) |\n| `pay.call(action, params)` | Escape hatch for any integration action |\n\n## Incoming webhooks\n\nConfigure a URL on the payments side (env `INTERNAL_WEBHOOKS`), then verify\neach delivery with `verifyPayWebhook`. The same secret used above unlocks it.\n\n```ts\nimport express from 'express';\nimport { verifyPayWebhook, isPayEvent } from '@agglabs-one/pay';\n\nconst app = express();\napp.post(\n  '/api/payments/webhook',\n  express.raw({ type: 'application/json' }),      // raw body is required\n  (req, res) => {\n    let event;\n    try {\n      event = verifyPayWebhook({\n        secret:  process.env.PAYMENTS_KEY_SECRET!,\n        rawBody: (req.body as Buffer).toString('utf8'),\n        headers: req.headers,\n      });\n    } catch (e) {\n      return res.status(401).end();               // bad signature — reject\n    }\n\n    if (isPayEvent(event, 'subscription.payment_succeeded')) {\n      const { subscriptionId, receiptUrl } = event.data;\n      // grant access / email the customer / etc\n    }\n\n    res.status(200).end();                        // ack — retry stops\n  },\n);\n```\n\nEvents emitted:\n- `invoice.paid`, `invoice.past_due`, `invoice.voided`, `invoice.refunded`\n- `subscription.created`, `subscription.updated`, `subscription.canceled`\n- `subscription.payment_succeeded` (with `receiptUrl` for the PDF)\n- `subscription.payment_failed`\n- `customer.card_added`, `customer.card_removed`\n- `webhook.test` (via `pay.webhooks.test()`)\n\nRetry schedule on the payments side: **30s → 5min → 30min → 3h → 12h**, then\n`dead`. Ack with any 2xx to stop retries.\n\n## Errors\n\nEvery failed call throws `AggError` (re-exported from `@agglabs-one/core`) —\n`err.code` matches the payments service's error taxonomy (`amount_below_min`,\n`no_card_on_file`, `unauthorized`, `unknown_action`, …), `err.status` is the\nHTTP status. Also re-exported: `InvalidKeyError`, `NotFoundError`, `ConflictError`.\n\n## Design notes\n\n- **Amounts in minor units on the wire**, major units on inputs where humans\n  care (`unitAmount: 29.99`). Fields ending in `Cents` are always integers.\n- **Same HMAC scheme both directions**: signed string\n  `\"<unix>.POST.<path>.<sha256(body)>\"`, hex HMAC-SHA256 with the shared secret.\n- **No Stripe SDK on your side** — `Pay` is the only import you need for the\n  server flow. The frontend still uses Stripe.js with the payments service's\n  publishable key to confirm `client_secret`s returned by\n  `pay.cards.setupIntent()`.\n","readmeFilename":"README.md","_rev":"1-128968dcec7fc0cb7219e5728ea5695f"}