{"_id":"@agentgates/paygates","_rev":"3-2594a11368d020cb05fc693e0d5944eb","name":"@agentgates/paygates","dist-tags":{"latest":"0.4.1"},"versions":{"0.3.2":{"name":"@agentgates/paygates","version":"0.3.2","keywords":["x402","x402 middleware","paywall","usdc","micropayments","api monetization","agent payments","402","express middleware","stablecoin"],"license":"MIT","_id":"@agentgates/paygates@0.3.2","maintainers":[{"name":"larptoearn","email":"cs@r3ference.com"}],"homepage":"https://paygates.dev","bugs":{"url":"https://github.com/Carlos-Sotop/agentgates-backend/issues"},"dist":{"shasum":"bb06313c3b1b6e282da8688eae0039abd04e6970","tarball":"https://registry.npmjs.org/@agentgates/paygates/-/paygates-0.3.2.tgz","fileCount":14,"integrity":"sha512-mgRea7aZlMCZ91G+IShuqfhOmE7V9oV7Edl708pMrK65uiaZKtBJQpKuwCZaq/YpvT+NL/p7cgUp745YhLzbzQ==","signatures":[{"sig":"MEQCIEOQsbFF0IpKr5OJA4kMR99u0n2bMTG+JsRbxJ/RqSqjAiBwwcyzkZHlGZkYFONjdxNQ38TkEfagM/6Cu1PVLubkOQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53982},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"66aff0cd79f038ab1a2bc207dce7a1cf41c4e8a8","scripts":{"test":"node --test test/*.test.mjs","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"larptoearn","email":"cs@r3ference.com"},"repository":{"url":"git+https://github.com/Carlos-Sotop/agentgates-backend.git","type":"git","directory":"packages/paygates"},"_npmVersion":"11.17.0","description":"Put a price on any route. Charge in USDC from inside your handler with a price your code computes; x402 middleware for a fixed-price route. Settles on Base, Polygon, Arbitrum, Ethereum and Solana.","directories":{},"_nodeVersion":"26.4.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/paygates_0.3.2_1788028228176_0.9151265128392507","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@agentgates/paygates","version":"0.4.0","keywords":["x402","x402 middleware","paywall","usdc","micropayments","api monetization","agent payments","402","express middleware","stablecoin"],"license":"MIT","_id":"@agentgates/paygates@0.4.0","maintainers":[{"name":"larptoearn","email":"cs@r3ference.com"}],"homepage":"https://paygates.dev","bugs":{"url":"https://github.com/Carlos-Sotop/agentgates-backend/issues"},"dist":{"shasum":"003028ea42e6c27ab657210c5b6104aec790b67d","tarball":"https://registry.npmjs.org/@agentgates/paygates/-/paygates-0.4.0.tgz","fileCount":20,"integrity":"sha512-dogUWktugBWWa9TagzEt9WxmLEGq2PJKXrnTal0W/4etkPDeZbaEPj5Q2XWxPB05nHJRRNVMXRGTAvS9ci4yCg==","signatures":[{"sig":"MEYCIQCk5PJsTD5JduLtg/7Wl+heYZuEJHaDIysyTOPleXTgmwIhAPq+kskkBwWUvVJi+aTpPw8kn/zJp6kVk/SF39hqdmS/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80085},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"187fa18206d83365920ca6b0d12f807a053c8d02","scripts":{"test":"node --test test/*.test.mjs","build":"tsc -p tsconfig.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"larptoearn","email":"cs@r3ference.com"},"repository":{"url":"git+https://github.com/Carlos-Sotop/agentgates-backend.git","type":"git","directory":"packages/paygates"},"_npmVersion":"11.17.0","description":"Put a price on any route. Charge in USDC from inside your handler with a price your code computes; x402 middleware for a fixed-price route. Settles on Base, Polygon, Arbitrum, Ethereum and Solana.","directories":{},"_nodeVersion":"26.4.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/paygates_0.4.0_1788670361012_0.289045567175354","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@agentgates/paygates","version":"0.4.1","description":"Put a price on any route. Charge in USDC from inside your handler with a price your code computes; x402 middleware for a fixed-price route. Settles on Base, Polygon, Arbitrum, Ethereum and Solana.","keywords":["x402","x402 middleware","paywall","usdc","micropayments","api monetization","agent payments","402","express middleware","stablecoin"],"license":"MIT","homepage":"https://paygates.dev","repository":{"type":"git","url":"git+https://github.com/Carlos-Sotop/agentgates-backend.git","directory":"packages/paygates"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"engines":{"node":">=18"},"scripts":{"build":"tsc -p tsconfig.json","test":"node --test test/*.test.mjs","prepublishOnly":"npm run build && npm test"},"devDependencies":{"typescript":"^5.4.0"},"gitHead":"70785157002cae0d67317ed8249c650641e22dc4","_id":"@agentgates/paygates@0.4.1","bugs":{"url":"https://github.com/Carlos-Sotop/agentgates-backend/issues"},"_nodeVersion":"26.4.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-xTO/+kFW5TCfKBPHIyBxtFh44lpvqI1eRHwDC2+Mr2S/O0n2BcdsivmMCDSKXgCs30+niwXMuljqctJgdjNSJg==","shasum":"333a361f851a99423f64e528b5efe015d9428b69","tarball":"https://registry.npmjs.org/@agentgates/paygates/-/paygates-0.4.1.tgz","fileCount":20,"unpackedSize":81083,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD1XTKNHsBjLWL3jwSGTDzbkRW7YoHVEZy6XqzaQn6h4AIhAN09fK81PYaTTO+cuhhgm9NuRwxOXX+CevF7DhXtvOis"}]},"_npmUser":{"name":"larptoearn","email":"cs@r3ference.com"},"directories":{},"maintainers":[{"name":"larptoearn","email":"cs@r3ference.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/paygates_0.4.1_1788674603314_0.16458933891767025"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-29T18:30:28.071Z","modified":"2026-09-06T06:03:23.602Z","0.3.2":"2026-08-29T18:30:28.300Z","0.4.0":"2026-09-06T04:52:41.142Z","0.4.1":"2026-09-06T06:03:23.450Z"},"bugs":{"url":"https://github.com/Carlos-Sotop/agentgates-backend/issues"},"license":"MIT","homepage":"https://paygates.dev","keywords":["x402","x402 middleware","paywall","usdc","micropayments","api monetization","agent payments","402","express middleware","stablecoin"],"repository":{"type":"git","url":"git+https://github.com/Carlos-Sotop/agentgates-backend.git","directory":"packages/paygates"},"description":"Put a price on any route. Charge in USDC from inside your handler with a price your code computes; x402 middleware for a fixed-price route. Settles on Base, Polygon, Arbitrum, Ethereum and Solana.","maintainers":[{"name":"larptoearn","email":"cs@r3ference.com"}],"readme":"# @agentgates/paygates\n\n**Put a price on any route.** Your code names the price; the buyer pays in USDC;\nyour handler runs once the money has landed.\n\n```js\nimport { paygateGate } from '@agentgates/paygates'\n\napp.post('/order', async (req, res) => {\n  const cart = await loadCart(req.body)\n\n  const gate = await paygateGate(\n    { price: cart.total, metadata: { order: cart.id, customer: cart.customerId } },\n    req,\n  )\n  if (!gate.paid) return gate.send(res)\n\n  await ship(cart, gate.receipt)\n  res.set(gate.headers).json({ ok: true, paidWith: gate.receipt.transaction })\n})\n```\n\n`cart.total` is a string like `'$12.40'` (or USDC micro as a digit string).\nYour code computes it, per request, the way you would hand an amount to any\npayment API. Nothing on your Agentgates page carries a price.\n\nA caller who has not paid gets an HTTP 402 with everything a wallet needs:\none entry per chain you can be paid on, each priced at that chain's own gas.\nA caller who has paid reaches the line after the gate, receipt in hand. You\nnever write wallet code, chain code or a signature scheme.\n\nThe same call inside a Next.js route handler, a Hono app, a Worker:\n\n```js\nexport async function POST(request) {\n  const cart = await request.json()\n  const gate = await paygateGate({ price: total(cart), metadata: { order: cart.id } }, request)\n  if (!gate.paid) return gate.response\n  return Response.json({ ok: true }, { headers: gate.headers })\n}\n```\n\n`paygateGate` takes an Express request or a Fetch `Request` and hands back\neither `{ paid: true, receipt, headers }` or the unpaid answer, ready to send\nthrough `gate.send(res)` or as `gate.response`.\n\n## metadata\n\nYour tag on the payment: an order id, a customer, a sku. A flat object of\nstrings, static or a function of the request. It comes back on the receipt,\nis stored beside the settle, and shows on each settle on your Agentgates page.\n\n```js\nconst gate = await paygateGate(\n  {\n    price: (request) => priceFor(request.body.sku),\n    metadata: (request) => ({ sku: request.body.sku, order: request.body.orderId }),\n  },\n  req,\n)\n```\n\nUnder Express the hooks receive `request.body` as your body parser left it.\nWith a Fetch `Request` you have already read the body, so compute the price\nand the tag and pass them in as values.\n\nCapped at 50 keys, 40 characters a key, 500 a value, 8 KB in all. Over the\ncap is a config error thrown in your process, never a charge and never a 400\nserved to your buyer.\n\n## The receipt\n\n```js\ngate.receipt\n// {\n//   transaction: '0x…',        // the on-chain transaction (base58 on Solana)\n//   network: 'base',\n//   payer: '0x…',              // who paid; base58 exact on Solana\n//   amountMicro: '12401600',   // your price plus that chain's settle, in USDC micro\n//   metadata: { order: 'A-1042', customer: 'c_91' },\n// }\n```\n\nPut `gate.headers` on the response you serve: it carries `X-PAYMENT-RESPONSE`,\nthe receipt the buyer's wallet reads. Confirmation is synchronous. Your handler\nruns only after the settle landed.\n\n## A human buyer\n\nThe unpaid answer carries `payUrl`: a hosted page where a person pays the same\nquote with one tap. Redirect them there, and tell the gate where they come\nback:\n\n```js\nconst gate = await paygateGate(\n  { price: cart.total, metadata: { order: cart.id }, returnUrl: 'https://yourstore.com/thanks' },\n  req,\n)\nif (!gate.paid) {\n  await saveQuoteId(cart.id, gate.body.payUrl)   // the id is the payUrl's last segment\n  return res.redirect(303, gate.body.payUrl)\n}\n```\n\nAfter paying, the buyer lands on your `returnUrl` with `?paygate=<id>`\nappended — the id of the quote that was paid. Your server confirms it before\nserving anything:\n\n```js\nimport { confirmPayment } from '@agentgates/paygates'\n\nconst confirmation = await confirmPayment(req.query.paygate)\nif (confirmation.paid) {\n  // confirmation.receipt: { transaction, network, amountMicro, paidVia }\n}\n```\n\nPass your key and the confirmation is bound to your account:\n\n```js\nconst confirmation = await confirmPayment(req.query.paygate, { apiKey: process.env.PAYGATES_API_KEY })\nif (confirmation.paid && confirmation.metadata?.order === orderId) { /* serve */ }\n```\n\nWith the key, a quote that is not one of your own sales answers `missing`,\nand your `metadata` tag comes back, so the order id you tagged the payment\nwith is the check. A refused key throws; it never silently falls back to the\nunbound read.\n\nWithout a key the read is open (the quote id is the capability) and carries\nno tag. Two things it will not do for you:\n\n- **The id alone proves a payment, not your sale.** Anyone can put somebody\n  else's paid id on your return URL. Match it against the quote id you stored\n  on the order when you quoted.\n- **A confirm that cannot run throws.** \"Could not confirm\" and \"not paid\" are\n  different facts; serve nothing on a throw and retry.\n\n## Gates register themselves\n\nThe first request a priced route serves registers it on your Agentgates page\nunder `METHOD /path` (Express hands over its route pattern, so `/items/:id`\nis one gate, not one per id). The row keeps the route, a name, what it earned,\nand a pause. There is nothing to type.\n\n## Install\n\n```sh\nnpm install @agentgates/paygates\n```\n\n```sh\nPAYGATES_API_KEY=agp_…\n```\n\nMint the key at [agentgates.ai](https://agentgates.ai) → Paygates. It can quote\nand settle for your account and nothing else: it holds no funds, names no\naddress, and cannot move a cent anywhere except into the payout destination you\nset yourself.\n\n## Where you get paid\n\nOne destination per chain, set on your Paygates page. A chain with no\ndestination is not offered, never another chain's address, because an address\non the wrong chain is money nobody can reach.\n\nThe `payTo` option in your code is a declaration we check, not the source of\ntruth. It makes the line say out loud where the money goes, and we tell you the\nmoment it stops matching your account. Leave it out and every destination you\nhave set up is offered.\n\nUntil you have set one up, the gate serves a 402 that says so: nothing is\ncharged and the caller has nothing to fix.\n\n## What it costs\n\nGas at cost. You keep every micro of your price. What the buyer pays on top is\nthe settle on that chain, and we take nothing above it.\n\nThe quoted settle carries a volatility buffer, because gas is read when the 402\nis quoted and paid when the payment lands, and a payment stays signable for up\nto fifteen minutes. It is a buffer, not a margin.\n\n## Selling things that ship\n\nThe default is for what arrives in the response: the payment settles to your\naddress the moment the request is served. For what arrives after it (a box, a\nbooking, a person's work) put the gate in escrow mode:\n\n```js\nconst gate = await paygateGate({ price: cart.total, fulfillment: 'escrow', metadata: { order: cart.id } }, req)\n```\n\nThe payment funds a non-custodial escrow under the delivery terms declared on\nthe gate (which proof of delivery you give, how long the buyer has to contest,\nthe ship-by deadline, the dispute tiers). Every term rides the 402, so the\nbuyer agreed to it before signing. You ship, you submit the proof, and the\nescrow releases to your address when the terms are met. The receipt carries\n`escrow: { orderId, escrowAddress }`.\n\nEscrow mode is not open on every deployment yet; until it is, an escrow gate\nserves a 402 that says so, and nobody is charged.\n\n## A route with one fixed price\n\nWhen every call costs the same, the middleware is one line:\n\n```js\nimport { paygate } from '@agentgates/paygates'\n\napp.use('/v1/summarize', paygate({ price: '$0.01' }))\napp.get('/v1/summarize', (req, res) => res.json({ summary: '…' }))\n```\n\nOr wrap a fetch-shaped handler:\n\n```js\nimport { paygateHandler } from '@agentgates/paygates'\n\nexport const GET = paygateHandler({ price: '$0.05' }, async (req, receipt) => {\n  return Response.json({ ok: true, paidWith: receipt.transaction })\n})\n```\n\n## Options\n\n| option | |\n| --- | --- |\n| `price` | `'$0.01'`, a digit string of USDC micro, or a function of the request returning one. Never a number: `0.07 * 1e6` is not 70000. |\n| `metadata` | your tag on the payment: a flat object of strings, or a function of the request. Echoed on the receipt. |\n| `fulfillment` | `'instant'` (default) or `'escrow'`. |\n| `returnUrl` | where the buyer lands after paying on the hosted page, https only; `?paygate=<id>` is appended. Static or a function of the request. |\n| `payTo` | optional. The destination you expect, checked against your account. |\n| `apiKey` | defaults to `PAYGATES_API_KEY`. |\n| `paygateId` | optional. Pin the call to one gate row; without it the route registers itself. |\n| `description` | the sentence the caller's wallet shows. Defaults to the method and path. |\n| `tollGraceBps` | how far under a re-quote a payment may land and still settle, in basis points of the settle portion. Default 2500; `0` compares exactly. |\n| `onSettled` | called with the receipt before your handler runs. |\n| `local` | default `true`: your 402s are built in your process from your setup, pulled once. `false` asks the facilitator for every quote. |\n\n## Your setup, pulled once\n\nThe first request on a route pulls your setup from the facilitator: where you\nget paid on each chain, the chain's USDC, the signing domain, the window. It\nis kept for an hour and refreshed in the background. From then on every\nunpaid request is answered in your process, with no round trip, and the\nfacilitator hears from you only when a payment settles. If the facilitator\nis unreachable, a copy up to a day old still answers your 402s.\n\nFour cases still quote remotely, because they need something only the\nfacilitator has: a human buyer (`Accept: text/html`, the hosted pay page), a\ngate with a `returnUrl` (you declared the pay page as your checkout, so every\n402 carries `payUrl`), an escrow sale, and a sticker above the micro\nthreshold (a commerce sale rides the contract). Switching a gate off on your dashboard takes effect at\nsettle, before any chain call, so a 402 already served charges nobody.\n\n## Chains\n\nBase, Polygon, Arbitrum, Ethereum and **Solana**, plus their testnets. The\nbuyer needs no gas token, ever: our relayer broadcasts and pays the chain.\n\n## Failure, honestly\n\n- A caller with no payment gets a 402 with prices. Normal.\n- A caller whose payment has already been used gets a **409**, never a fresh\n  price. Re-quoting somebody who already paid is how a buyer pays twice.\n- A mistake in your own code (no price, metadata over the cap, a key that was\n  refused) is thrown in your process. It is never served to a caller as their\n  error, and the route is never served for free.\n- If the facilitator itself is unreachable, the gate answers 503 and asks for\n  the same request again.\n\n## The API is the product\n\nThe four facilitator calls (`/supported`, `/verify`, `/quote`, `/settle`) are\nwhat this package wraps, for Node. An agent integrating for its owner, or a\nstack in another language, reads the API directly.\n\n## Licence\n\nMIT.\n","readmeFilename":"README.md"}