USDC per call. No API keys. No signup. Agents discover the lab, settle with a USDC micro-payment via the x402 protocol, and consume — autonomously.
SVM402 is the Solana x402 conformance and resilience lab for AI agents: 14 deterministic x402 failure scenarios on the real money path, free payment diagnosis, paid on-chain settlement receipts. Built for agent builders, x402 client SDK authors, self-facilitating sellers, and agents doing preflight — everyone whose money is on the line the moment a request carries a payment. Rehearse the challenge, verify, settle and receipt machinery on devnet, then on mainnet — the lab's enforce/settle path IS the production gateway's, so the rehearsal is the production behavior, not a simulation.
- Base URL: https://svm402.com · devnet lab: https://lab-devnet.svm402.com
- Network per challenge: the server's CAIP-2 id — Solana mainnet
solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpor devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 - Asset: USDC (6 decimals; integer base-unit strings over the wire)
- Payment: x402 protocol v2 — exact-scheme USDC transfers, facilitator settles; the facilitator is the fee payer, so the buyer needs USDC only
What it is:
- A living lab for the x402 protocol on Solana: tiny paid routes your agent settles with a USDC micro-payment, plus fourteen deterministic failure scenarios (slow serve, verify-time rejection, settle timeouts, facilitator failover, replay protection, expired blockhashes, …) executed on the REAL money path — challenge, verify, settle, serve, receipt.
- Exactly how YOUR x402 client behaves before, during and after settlement: the charged responses, receipts and retry credentials come from the same enforce/settle machinery the production gateway runs — not a mock.
- Fully self-describing: full payment requirements per route at
/.well-known/x402, an OpenAPI 3.1 spec with live prices, and an agent quick-reference at/llms.txt.
What it is not:
- A data service. The lab sells payment behavior, not data.
- A key or account requirement: any generic x402 v2 client works; the payment is the auth.
Every paid route answers a 402 challenge first; the buyer signs an exact-scheme USDC transfer and the facilitator settles it. Amounts on the wire are integer base-unit strings (1000 devnet / 2000 mainnet) — never floats. The challenge's PAYMENT-REQUIRED header and the x-x402-price extension are the only price sources. Scenario walks charge the same lab rate as the ping.
| Method | Path | Price per call | What it proves |
|---|---|---|---|
| GET | /v1/ping |
$0.001 devnet / $0.002 mainnet |
The smallest paid call: one request proves your whole x402 v2 round trip — 402 challenge → signed transfer → facilitator verify + settle → 200 whose payment block carries the payer, the settled amount (integer USDC base units), the transaction hash, the explorer link, the facilitator name + fee payer, and verify/settle timings. |
| GET | /v1/echo |
$0.001 devnet / $0.002 mainnet |
The echo's GET twin: same price, same settlement; body null and the raw query (?a=1&b=two) mirrors exactly. |
| POST | /v1/echo |
$0.001 devnet / $0.002 mainnet |
The anything-mirror for client debugging: after the settle it echoes EXACTLY what the gateway received — method, path, raw query, parsed body (up to 16 KB; a bigger body is rejected 413 BEFORE any settle, so an unservable body is never charged), sha256 over the raw bytes, and an allowlisted headers_seen where the payment header is redacted and authorization/cookie never appear. |
| GET | /v1/scenario/{name} |
$0.001 devnet / $0.002 mainnet |
Rehearse one deterministic failure walk (the list below) on the REAL verify/settle machinery; the response carries X-Lab-Scenario: name; step=N and progress is monotonic per X-Lab-Client-Id — "send it again" advances the same ladder. |
| POST | /v1/scenario/{name} |
$0.001 devnet / $0.002 mainnet |
The POST spelling of the same walk. |
| GET | /v1/receipt/{signature} |
$0.001 devnet / $0.002 mainnet |
The paid on-chain settlement receipt by transaction signature — one getTransaction through the lab's shared RPC token bucket, cached by chain finality; a drained budget answers 503 BEFORE any challenge. |
| Method | Path | Price | What it gives you |
|---|---|---|---|
| GET | /v1/scenarios |
free | The scenario engine's manifest: every walk's name, price, params, mainnet policy and expected status sequence, plus the live lab metrics (issued / redeemed / expired / charged_unserved). |
| GET | /v1/scenario/redeem?client_id= |
free | The recovery lane: serves a previously settled but unserved scenario charge ONCE, free — binding-first (exact path + body fingerprint + payer), single-use; unknown or consumed credentials answer 404, never an error. |
| POST | /v1/scenario/redeem |
free | The any-method spelling of the recovery lane. |
| GET | /v1/status |
free | The operational snapshot: each facilitator's probe health (last_probe_at, probe_ms_p50, the 3-failure breaker), the lab's 24 h settles / charged-unserved / open-credential counters, the fee payer's balance (a background refresher — the route never calls RPC) and the 24 h ping p95. Data older than 90 s answers 503 — never stale-as-fresh. |
| POST | /v1/diagnose |
free | The payment grader: grade a SIGNED x402 payment (and the challenge it answers) before you send it. 41 offline checks, then 4 ledger checks on at most 2 RPC calls. 200 always — the verdict (ok | warnings | fail) is data. |
| GET | /health |
free | The gateway's own liveness. |
Each walk advances per client id; replaying lands on the same step and answers the same verdict, forever. Policy badges reflect how mainnet gates each one. The full walkthroughs — including the payment-header grammar — are in /llms.txt.
ok— verify, settle, 200: the control; every attempt serves. mainnet: yesslow— settle, sleep?delay_ms=(0..15000, default 5000), then 200 — the sleep is real, the decision is clock-free. mainnet: yesverify_reject— a 402 with?reason=(amount | network | asset | expired); no facilitator call, nothing settles. mainnet: yesretryable_503_before_settle— 503{retryable:true}after verify, BEFORE settle; the next attempt serves. mainnet: yesprice_change— a 402 carrying a rotated price (2x devnet; +1000 base units mainnet); paying the new challenge serves. mainnet: yesfeepayer_rotation— a 402 whoseextra.feePayernames the backup facilitator; the re-signed attempt settles via the backup. mainnet: yesreplay— the settlement is real exactly once; resending the identicalPAYMENT-SIGNATUREanswers 402 (already used), no second transfer. mainnet: yesexpired_blockhash— the challenge carriesextra.recentBlockhash= a known-expired sentinel; a payment built on it answers 402blockhash_expiredwith a fresh challenge. mainnet: yesbackend_error_after_settle— settle confirmed, then 502 + the durable retry credential;X-Retry-Settlementserves free once, reuse falls through to a normal 402. mainnet: opt-in — needsX-Lab-Accept-Fault: 1settled_503_retry_credential— settle, then 503{status:"settlement_pending", retry_after_s: 2}WITH the credential; retry free once. mainnet: opt-in — needsX-Lab-Accept-Fault: 1settle_timeout_then_confirm— the first settle wait times out client-side while the broadcast proceeds; the late confirm completes the real settle (200 arrives slow). mainnet: yesfacilitator_down— the primary is unhealthy for this request only; the backup's challenge is paid and served via the backup. mainnet: yesdrop_connection_after_settle— settle, then destroy the TCP socket (devnet only); the credential stays redeemable at/v1/scenario/redeem. devnet onlymethod_mismatch— a paid GET answers 405 +Allow: POSTbefore any verify; POST rides the money path. mainnet: yes
Charged-but-unserved faults (the settled 502 / 503 / drop walks) issue a durable, single-use retry credential — the client is never charged without a way back. The manifest at /v1/scenarios publishes the live charged_unserved counter.
Base URL: https://lab-devnet.svm402.com · CAIP-2 network id: solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1.
-
Get devnet SOL for your agent's keypair:
solana airdrop 2 --url devnet
-
Get devnet USDC from the Circle faucet for the Circle devnet mint:
4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU -
Call the lab's devnet deployment with an
@x402/svmclient — the 402 → sign → retry loop is automatic on x402 clients, and the facilitator is the fee payer, so you need USDC only:// Node: @x402/fetch wraps fetch with the x402 v2 payment loop; // @x402/svm signs the exact-scheme USDC transfer for Solana. import { x402Client, wrapFetchWithPayment } from "@x402/fetch"; import { ExactSvmScheme, toClientSvmSigner } from "@x402/svm"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import bs58 from "bs58"; // 1. your agent's devnet keypair -> an x402 client signer const keypair = await createKeyPairSignerFromBytes(bs58.decode(process.env.AGENT_SECRET_KEY)); const client = new x402Client(); client.register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme(toClientSvmSigner(keypair))); // 2. wrap fetch: 402 -> sign -> automatic retry const paidFetch = wrapFetchWithPayment(fetch, client); const res = await paidFetch("https://lab-devnet.svm402.com/v1/ping"); // GET /v1/ping → 402 + PAYMENT-REQUIRED (base64: amount, payTo, asset, fee payer) // → your @x402/svm signer signs the transfer // → automatic retry with the signed envelope → 200 with the // PAYMENT-RESPONSE settlement receipt header
-
Then run a scenario — same price as the ping, on the same machinery:
const walk = await paidFetch("https://lab-devnet.svm402.com/v1/scenario/ok"); // every scenario: GET|POST /v1/scenario/{name} — X-Lab-Scenario: name; step=N
The same client works against mainnet (https://svm402.com, CAIP-2 solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp) at the mainnet rate ($0.002 per call) — see the disclaimer below.
- Call any paid route. You receive HTTP 402 with a base64-encoded
PAYMENT-REQUIREDheader describing an exact-scheme USDC payment (amount in base units,payTo, asset, CAIP-2 network, fee payer). ThepayTowallet comes from the live challenge —/.well-known/x402publishes it per route; nothing to pin here. - Sign that transfer with an x402 v2 client —
@x402/fetch+@x402/svm, AgentCash, or any x402 v2 wallet. The facilitator is the fee payer, so the buyer needs USDC only (no SOL for fees). - Retry the request with header
PAYMENT-SIGNATURE: <signed payment envelope>. - On success the response carries a
PAYMENT-RESPONSEreceipt header (mirrored asX-PAYMENT-RESPONSE) with the settlement hash.
Charged but not served (a facilitator or gateway failure after settlement)? Retry the SAME failed request ONCE with header X-Retry-Settlement: <request id from X-Settlement-Request-Id> — the gateway serves that request free, without a new payment. The credential is SINGLE-USE and valid only for the FAILED request it was issued for (same path, same body): a request already answered with a 200 is never replayable free. Settled 502/503 responses carry Retry-After (seconds) — honor it; the gateway may have already recorded the late settle, and the retry then serves instantly.
GET /v1/receipt/{signature}?pay_to=&amount=&asset=&network= reports what the chain says about a settle: one getTransaction, finality-aware cache (finalized and failed are cached forever; not_found / confirmed / processed for 10 s). The body reports chain status, slot, block time, fee lamports, the fee payer (labeled), the FIRST USDC transfer matching your pay_to, amount and asset query, and per-check booleans (pay_to, amount_gte, asset, exactly_one_matching_transfer); not_found is an honest 200. A drained RPC budget answers 503 before any challenge; a budget or RPC failure after your settle answers 503 WITH the live retry credential — you are never charged-and-unserved without a way back.
POST /v1/diagnose grades a SIGNED payment against the 402 challenge it answers: 41 offline checks (envelope ↔ challenge ↔ wire — accepted-copy mismatches including the stale fee payer, the client's ed25519 signature over the exact message bytes, transferChecked semantics, compute-budget discipline), then 4 ledger checks on at most two RPC calls. 200 always — the verdict is data, never an HTTP error. A 32 KB raw-byte cap answers 413, and 30 runs/minute/IP answers 429.
The request — a signed payment and the challenge it answers:
POST /v1/diagnose
{"payment": "<base64 x402 v2 payment envelope>",
"challenge": { …the raw 402 body the payment answers… }}
A budget refusal or RPC failure is reported as skipped with the reason — never a 5xx. The audit line keeps only the payload's sha256; your bytes leave no trace.
Challenges settle through Coinbase CDP first, then our own Solana-native facilitator (facilitator.svm402.com) as backup, then PayAI as last resort — automatic failover keeps payments settling if any incumbent stops. Each facilitator's probe health is published at GET /v1/status.
Gas note: a settle costs ≈ 10,001 lamports — the facilitator pays the SOL fee (it is the fee payer on every challenge); you pay USDC only.
| Surface | Purpose |
|---|---|
GET /.well-known/x402 |
x402 payment discovery metadata — every route with FULL payment requirements (CAIP-2 network, amount, payTo, asset, fee payer per resource) |
GET /openapi.json |
OpenAPI 3.1 spec with an x-x402-price extension on every paid operation |
GET /llms.txt |
The agent quick-reference: payment-header grammar, scenario walkthroughs, the payment flow |
Bazaar indexing: MAINNET challenges carry a Bazaar declaration (extensions.bazaar, category Infrastructure) per paid route; devnet never publishes one — test routes are not indexed.
No per-vendor install needed: any generic x402 v2 client discovers and pays the lab with zero setup.
👉 AgentCash (recommended): npx -y agentcash@latest, then discover https://svm402.com — it lists every route and live price; agentcash fetch <url> handles payment automatically.
This is a PAYMENT lab: every charged call settles a real USDC transfer on the chain the URL serves. Rehearse on devnet first; mainnet charges are real money. The lab sells payment behavior, not data, and carries no other warranty.
- Service: https://svm402.com · Devnet lab: https://lab-devnet.svm402.com
- x402 protocol: https://www.x402.org
- Client: any generic x402 v2 client — AgentCash recommended:
npx -y agentcash@latest