Where do spending limits and policy actually sit in an x402 payment flow?
x402 (HTTP 402 Payment Required) lets a machine pay for an API call: the server quotes a price, the client submits a signed payment, a facilitator settles it, and the response arrives. It is a clean answer to how an agent pays. It does not answer whether this payment should happen under your rules — budgets, recipient policy, approval thresholds, replay discipline. Those live around the rail, in an authorization layer that runs before execution.
A payment protocol optimizes for one thing: moving money correctly once it is authorized. It is not the right home for your spending policy, for the same reason a card network isn't your corporate expense policy:
agent wants a paid API result
│
▼
SpendShield.authorize(amount, recipient, agent) ← your policy, atomic
│
├── ALLOW → signed one-time grant
├── APPROVAL → human approves → grant
└── DENY → the x402 flow never starts
│
▼
executor verifies grant (once; replay refused)
│
▼
x402 flow: quote → sign → facilitator → settle → result
│
▼
budget accounted atomically + audit event
Neither the x402 server nor the facilitator changes. SpendShield slots into the client side (and can gate a
paywall server side too) — the
x402 adapter shows both shapes: protect_x402_payment before submitting, and a paywall guard before
settling a resource.
from spendshield.adapters.x402 import protect_x402_payment
# client side: gate before submitting the payment
ok = protect_x402_payment(
guard, amount=0.05, to="weather-api.example.com",
agent="research-agent", dry_run=True)
# → ALLOW: proceed with the x402 quote/sign/settle flow
# → DENY : do not sign, nothing is submitted
# policy.yaml — same policy language as any other rail
version: "2.1.0"
policy:
budget: { daily: 5 } # $5/day of paid APIs
transaction: { max: 1 }
merchants:
allowed: [weather-api.example.com, search.example.com]
blocked: [unknown-facilitator.example]
approval: { over: 0.5 }
| Paid API request | Outcome |
|---|---|
| $0.05 → weather-api.example.com (within daily budget) | ALLOW → x402 flow proceeds |
| $0.70 → weather-api.example.com (over approval line) | APPROVAL → human decides |
| $0.05 × 60 calls (cross-call) | budget window hit — later calls DENY even though each fits the cap |
| $0.05 → unknown-facilitator.example | DENY — recipient not allowed |
SpendShield is the authorization layer that sits in front of x402 (or any rail): deterministic ALLOW / APPROVAL / DENY, signed one-time grants, atomic budget accounting, tamper-evident audit. Open source, MIT, Python + MCP — and rail-agnostic, so the same policy keeps working if you later add Stripe, a wallet, or a second protocol.
pip install spendshieldspendshield/adapters/x402.py