cd /news/ai-agents/funded-key-with-limits-or-approve-ea… · home › topics › ai-agents › article
[ARTICLE · art-160742] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Funded key with limits, or approve each payment? Putting a spend policy between an AI agent and HTTP 402

A developer built spendctl, a local sidecar that sits between an AI agent and HTTP 402 payment endpoints (x402/MPP), keeping the private key and spend policy outside the model. The sidecar enforces per-request and daily budgets, domain allowlists and human approval thresholds, and adds an explicit 'unknown' ledger state for payments that settle while the paid API times out, backed by idempotency keys and a manual resolve command. A hosted sandbox is available as a remote MCP server with tools including sandbox_pay, check_budget and approve.

by read3 min views1 publishedOct 30, 2026

Agents can pay for APIs now. With x402 and MPP a server answers 402 Payment Required with a price, the client signs a stablecoin authorization, retries, and gets the data. No API key, no invoice, no account. It works, and it is the part people demo.

The part nobody demos is who decides. Two patterns keep coming up:

Both put the money decision inside the agent's reach: in a prompt, in a tool argument, in an environment variable the model can read. I wanted the decision outside the model, in something a human writes once and can audit later. That became spendctl, a local sidecar. This post is about the design, including the one state that turned out to matter most.

The agent never holds a key. It sends its HTTP request through the sidecar instead: as a gateway URL, through HTTP_PROXY, with a wrapFetch in the SDK, or as an MCP pay tool. When the seller answers 402, the sidecar does three things:

$0.40 would exceed the daily budget of $0.25 for agent researcher, $0.21 already spent"), not as a stack trace.

agents:
  researcher:
    budget: { perRequest: "0.05", daily: "0.25" }
    allow: ["api.example.com"]
    requireApprovalAbove: "0.02"

The model sees a budget, a refusal or an approval id. It never sees a private key, and it cannot change the policy.

A payment that crosses the threshold needs a human. Two modes:

X-Spendctl-Approval: <id>. One approval pays for exactly one retry, and it is bound to what the human saw: recipient, network, asset, amount. If the seller's next 402 asks for anything else, the retry is refused and nothing is paid. Humans approve from the CLI, a local dashboard, or a review link in a Slack or Discord webhook. Agents cannot approve; the admin token lives in a file the agent does not read.

Someone on r/x402 asked the question that every payment system eventually has to answer: the payment settles, but the paid API times out before the agent gets the result. Does the ledger know the difference?

Most agent payment demos do not model this at all. A retry is a second payment. spendctl has an explicit state for it:

settled (the seller answered 2xx with a settlement receipt), failed (the seller rejected it), or unknown`` Idempotency-Key inside the window, the sidecar refuses and points at the original row, so paying twice takes deliberate effort.spendctl resolve <id> --settled --tx 0x… or --failed after checking the chain or the seller's dashboard. This is not clever. It is the boring bookkeeping that is missing from most "let the agent pay" code, and it is where the money actually leaks.

There is a hosted sandbox: a real sidecar running against mock paid APIs, exposed as a remote MCP server at https://mcp.spendctl.dev/mcp. Add it to Claude, Claude Code, Cursor or VS Code, then ask the model to create a sandbox, make a paid call, blow the budget, hold a payment for approval and approve it. Throwaway wallet, mock facilitator, no outbound network, nothing real. The tools are sandbox_create, sandbox_pay, check_budget, list_receipts, get_policy and approve.

Locally:

npx spendctl init && npx spendctl start   # sidecar on :8402
npx spendctl mock                          # mock facilitator + two paid APIs
npx spendctl fetch "http://localhost:4022/search?q=x402" --agent researcher

await_approval tool that long-polls under the client timeout is under consideration, after a good suggestion in the r/mcp thread. If you are putting agents in front of paid APIs, I would like to hear which ledger fields you would want to see, and what your clients actually do when a payment is held. Docs are at spendctl.dev/docs; the sandbox needs no account.

── more in #ai-agents 4 stories · sorted by recency
── more on @spendctl 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/funded-key-with-limi…] indexed:0 read:3min 2026-10-30 · —