Can you hand an agent an API key and a cap, and have it find services, pay for them, and be stopped — with no per-provider accounts, no protocol knowledge, and no keys of its own?The run below is real. Every number, hash and error on this page came from one execution against live merchants on Base mainnet and Tempo mainnet. Total cost: $0.08.
The refusal is the interesting part. Anyone can demo a purchase. What makes an agent safe to leave running is a spend control that says no — and keeps saying no — without you being there. That’s step 6, and it’s the reason this page exists.
What the agent is given
Two things. That’s the whole grant:
It is not given: a wallet, a private key, a merchant account, an API key for any service it buys from, or any knowledge of which payment protocol a service speaks.
1. Discover
The catalog is public. No key, no account, no signup:targetUrl, the endpoint path and method, and a priceLabel:
?search= matches titles, descriptions and categories — not slugs. To fetch one known service, use the by-slug route above. limit is capped server-side at 20, so paginating the whole catalog client-side isn’t the answer either.2. Set the budget
The cap is chosen so the third purchase cannot fit:3. Buy over MPP
The agent sends a URL and a delegation id. Nothing else:4. Buy over x402
Now the same call shape against a service on a different protocol and a different chain:WWW-Authenticate: Payment on one and PAYMENT-REQUIRED on the other, and chose the rail itself — signing an EIP-3009 authorization on Base for one and a native Tempo charge for the other.
The agent does not know, and does not need to know, which chain it just paid on.
5. Report
One ledger, regardless of protocol or chain:
Both reconcile exactly against the chains: Base −0.010000 USDC, Tempo −0.060029 USDC.e (the 0.060001 payment plus 28 units of gas, which Tempo bills in the stablecoin itself).
On the MPP rail,
network comes back as a bare name — "tempo" — with no chain id, so it does not distinguish Tempo mainnet (4217) from the Moderato testnet (42431). That makes the asset address the only field that tells you which chain a payment actually settled on. The two token addresses, and why they are easy to misread, are in the MPP rail.&format=csv for a downloadable file. This is the same record whether you spent over one protocol or five.
6. Refused
The agent tries the CoinGecko call once more. It has 1¢ left; the call costs 7¢:402. No payment minted, no credential issued, nothing to unwind — the ledger still holds exactly two payments. The cap is enforced server-side inside the same transaction that records the spend, so an agent cannot get past it by retrying, looping, or being confidently wrong about its own remaining budget.
That is the property that makes an autonomous agent something you can leave running: the ceiling is not enforced by the agent’s good behaviour.
0003 covers exhausted, expired and revoked. Read remainingBudgetCents and expiresAt from GET /api/v1/delegation/{id} to tell them apart — a long-running agent that worked yesterday has very often just aged out rather than overspent. See Guardrails.What this demonstrates
- Discovery needs no account. The catalog is public and machine-readable, and carries enough to place a call.
- One integration, many protocols. The agent wrote no protocol-specific code. Adding a rail is the Router’s problem, not the agent’s.
- The agent holds nothing. No wallet, no private key, no merchant credentials. Funds sit in a custodial wallet it cannot reach except through a capped Delegation.
- Spending is bounded by construction. The cap is checked server-side on every payment, and refusing costs nothing.
- Everything is auditable. One ledger across every rail, with on-chain hashes that reconcile.
Reproducing it
The sixcurl calls above are the whole run. There is nothing else to install — a live API key, a Delegation, a funded wallet, and the requests on this page reproduce it end to end in any shell or language.
Before a first run, check the things that most often turn into a “Router bug” that was nothing of the sort:
- Read the wallet address back from the live Delegation (
providerPaymentMethodId), never from anything you wrote down — funding a stale address fails as402 BCK.ROUTER.0009, which deliberately does not name the address it checked. - Fund it on both chains you intend to pay on. Base and Tempo are separate balances.
- Confirm the merchant still answers
402on the rail you expect. A service that stops charging is relayed withpaid: false, and a run can otherwise “succeed” having bought nothing. - Check the catalog is loaded, not serving placeholder rows — compare
totaland look at thetargetUrls.
Nevermined staff: a scripted version of exactly this run — the six steps plus a preflight covering every point above — lives in the internal
nvm-monorepo repository at .claude/skills/nvm-router-demo/. It adds --dry-run (spends nothing) and --selfcheck (offline). It is not public, and nothing on this page depends on it.Next
Guardrails
Every check the Router makes before it signs, and every error code it can return.
Ledger
The unified payment record, its fields, and CSV export.