{"schema_version":"1.0","publisher":"Primitive SDKs","canonical_url":"https://test.abhinandan.one/x402-payments-overview-04a296ff/node-sdk-x402-spend-policy","markdown_url":"https://test.abhinandan.one/x402-payments-overview-04a296ff/node-sdk-x402-spend-policy.md","article":{"id":"7fce1668-4a83-4edc-bcfa-74176e0bf04b","article_slug":"node-sdk-x402-spend-policy","parent_article_slug":"x402-payments-overview-04a296ff","parent_article_title":"x402 Payments Overview","kind":"guide","published_at":"2026-08-11T18:54:58.058487+00:00","keywords":["setSpendPolicy","getSpendPolicy","listPayoutAddresses","x402 spend policy","max_per_payment","max_per_day"],"meta_description":"setSpendPolicy merges a paused kill-switch, per-payment and daily USDC caps, and a payee allowlist onto your org's outbound x402 payments.","og_image_url":null,"source_file_paths":["sdk-node/README.md","sdk-node/src/x402/client.ts"],"recording_id":null,"replayable":false,"task_name":"Spend Policy and Payout Address Management","category":"Node.js SDK","summary":null,"description":"Guard outbound x402 payments with an org-level kill-switch, per-payment and daily caps, and a payee allowlist, and inspect the payout addresses your org has registered.","content_kind":"repo_page","content_markdown":"Every outbound x402 payment your org makes with `pay()` is checked against a **spend policy**: a paused kill-switch, per-payment and daily caps in token base units, and an allowlist of payee orgs. Reach for this page when you need to cap exposure before handing out payment credentials to an agent, or when you need to see which wallet addresses your org has already registered as payout destinations.\n\nFor the payment flow itself (registering a payout address as payee, creating a challenge, paying it), see [Charging and Registering Payout Addresses](node-sdk-x402-charging) and [Paying a Challenge](node-sdk-x402-paying). This page covers the two read/update operations that sit alongside that flow: `getSpendPolicy` / `setSpendPolicy` and `listPayoutAddresses`.\n\n## What the spend policy controls\n\nThe [spend policy](x402-payments-overview) is the org-level guardrail on outbound x402 payments, with four fields: a `paused` kill-switch, a `max_per_payment` cap, a `max_per_day` cap (both in token base units), and an `allowlist` of payee org ids.\n\n<Info>\n\nThe spend policy guards **outbound** payments only, payments your org makes with `pay()`. It has no effect on payments your org receives via `charge()`.\n\n</Info>\n\n| Field | Type | Meaning |\n| --- | --- | --- |\n| `paused` | `boolean` | Kill-switch. When `true`, every outbound payment is refused. |\n| `max_per_payment` | `string \\| null` | Per-payment cap, in token base units. `null` means no cap. |\n| `max_per_day` | `string \\| null` | Daily cap, in token base units. `null` means no cap. |\n| `allowlist` | `string[] \\| null` | Allowed payee org ids. `null` means any on-net payee is allowed; `[]` denies every payee. |\n\nUSDC has 6 decimals, so a cap of `\"5000000\"` is 5.00 USDC.\n\n## Read the current policy\n\nCall `getSpendPolicy()` on the x402 client to read all four fields as the server currently holds them.\n\n```typescript\nimport { createX402Client } from \"@primitivedotdev/sdk/x402\";\n\nconst x402 = createX402Client({ apiKey: process.env.PRIMITIVE_API_KEY! });\n\nconst policy = await x402.getSpendPolicy();\nconsole.log(policy);\n// {\n//   paused: false,\n//   max_per_payment: \"5000000\",\n//   max_per_day: null,\n//   allowlist: null,\n// }\n```\n\n## Update the policy\n\nCall `setSpendPolicy()` with only the fields you want to change; omitted fields keep their current server-side value.\n\n<Steps>\n\n<Step title=\"Decide which fields to change\">\n\n`setSpendPolicy` **merges**: only the fields you pass in the update change, and any field you omit keeps its current server-side value. There is no full-replace mode, so you never need to re-send the whole policy just to change one field.\n\n</Step>\n\n<Step title=\"Call setSpendPolicy with only those fields\">\n\n```typescript\n// Cap every single payment at 5.00 USDC (5,000,000 base units).\n// paused and allowlist are left untouched.\nawait x402.setSpendPolicy({ paused: false, max_per_payment: \"5000000\" });\n```\n\n</Step>\n\n<Step title=\"Pass null to clear a cap\">\n\n`null` is a real value here, distinct from omitting the field. Passing `null` explicitly removes a previously-set cap:\n\n```typescript\n// Remove the daily cap; max_per_payment (and paused, allowlist) are unchanged.\nawait x402.setSpendPolicy({ max_per_day: null });\n```\n\n</Step>\n\n<Step title=\"Verify with a fresh read\">\n\n```typescript\nconst updated = await x402.getSpendPolicy();\nconsole.log(updated.max_per_payment); // \"5000000\"\n```\n\n</Step>\n\n</Steps>\n\n### Kill-switch: pause all outbound payments\n\nSetting `paused: true` refuses every outbound payment regardless of caps or allowlist. Use it as an emergency stop when you suspect an agent is misbehaving:\n\n```typescript\nawait x402.setSpendPolicy({ paused: true });\n```\n\n### Allowlist a fixed set of payee orgs\n\n`allowlist` takes payee org ids. `null` (the default) allows any on-net payee; an empty array denies every payee, which is useful for a policy you want fully closed until you explicitly open it:\n\n```typescript\n// Only allow payments to two specific payee orgs.\nawait x402.setSpendPolicy({\n  allowlist: [\"org_9f2a1b\", \"org_44de70\"],\n});\n\n// Deny every payee (fully closed).\nawait x402.setSpendPolicy({ allowlist: [] });\n\n// Allow any on-net payee again.\nawait x402.setSpendPolicy({ allowlist: null });\n```\n\n<Warning>\n\nSetting `allowlist: []` denies every payee, so every subsequent `pay()` call your org makes is refused. Confirm this is the intended blast radius before applying it in production.</br>\n\n</Warning>\n\n<Tip>\n\nCombine `max_per_payment` with `max_per_day` for defense in depth: `max_per_payment` bounds the damage from a single runaway call, `max_per_day` bounds it across a burst of calls.\n\n</Tip>\n\n## List registered payout addresses\n\n`listPayoutAddresses()` returns every payout address your org has registered as a payee, each with its network, label, default flag, and verification timestamp. The one-time x402 payout address registration step is covered in [Charging and Registering Payout Addresses](node-sdk-x402-charging).\n\n```typescript\nconst addresses = await x402.listPayoutAddresses();\nconsole.log(addresses);\n// [\n//   {\n//     id: \"...\",\n//     address: \"0x1111111111111111111111111111111111111111\",\n//     network: \"base-sepolia\",\n//     label: \"treasury\",\n//     is_default: true,\n//     verified_at: \"2026-01-01T00:00:00.000Z\",\n//   },\n// ]\n```\n\nRegistration is per network, so an org can hold a default payout address on `base-sepolia` and another on `base`. `charge()` resolves its `pay_to` from this directory, which is why you register before requesting payments.\n\n## Errors\n\nEvery method on the x402 client, including `getSpendPolicy`, `setSpendPolicy`, and `listPayoutAddresses`, throws `X402Error` on a client-side, transport, or non-2xx server error. `X402Error` carries `status` (`0` for a request that never reached the server), `body`, and `retryAfter`. See [Node.js SDK Errors](node-sdk-errors) for the full `X402Error` shape (`status`, `body`, `retryAfter`) and how to distinguish a request that never reached the server from a server-side rejection.\n\n## Next steps\n\n<CardGroup cols={2}>\n\n<Card title=\"Charging and Registering Payout Addresses\" href=\"node-sdk-x402-charging\">\n\nRegister a payout address as payee and create payment challenges with charge().\n\n</Card>\n\n<Card title=\"Paying a Challenge\" href=\"node-sdk-x402-paying\">\n\nSign and submit payment for an x402 challenge as the payer.\n\n</Card>\n\n<Card title=\"x402 Payments Overview\" href=\"x402-payments-overview\">\n\nUnderstand the full non-custodial payment model shared across every SDK.\n\n</Card>\n\n<Card title=\"Node.js SDK Errors\" href=\"node-sdk-errors\">\n\nLook up X402Error and every other error type the SDK can raise.\n\n</Card>\n\n</CardGroup>","canonical_base_url":"https://test.abhinandan.one","seo_indexing_enabled":true,"last_modified":"2026-08-21T18:22:43.359885+00:00","video_url":null,"voiceover_url":null,"tools_used":[],"demonstrated_by":[],"steps":[],"related_links":[],"intro":null,"prerequisites":[],"verification":[],"troubleshooting":[],"suggest_edit_url":"https://github.com/abhi-browzer/primitive-sdks/edit/main/sdk-node/README.md","raise_issue_url":"https://github.com/abhi-browzer/primitive-sdks/issues/new?title=Docs+feedback%3A+Spend+Policy+and+Payout+Address+Management&body=Page%3A+https%3A%2F%2Ftest.abhinandan.one%2Fnode-sdk-x402-spend-policy","page_feedback_enabled":true,"verified_ref":null,"verified_at":"2026-08-11T18:38:45.205849+00:00"}}