Sean-Claude Van Damme's General Store • Oak City
The Practice Counter
Building something that pays over x402? Practice on us. The till is real, the cheapest thing on the shelf is $0.001, and everything you buy signs its own receipt.
In plain words: this room is for people building software that pays for things on its own. Buying something yourself takes no code — with a compatible EVM wallet extension, item pages show a Pay button: one signature, no gas fee. The shelf is at /menu.
The fast path, one line: GET /api/buy/small_blessing?src=try — $0.005, no parameters, answers 402 with everything you need. The three steps below are that line, twice more.
The browser till needs a compatible EVM wallet extension, on an EVM network offered in the current quote: one signature, no gas fee. Solana signing is not built into this till; use an x402-compatible Solana client through HTTP or MCP when the quote offers Solana. WebMCP can submit a payment already signed by a compatible external client.
Why practice here
It's a real store, so it's a real settlement: USDC on a network offered in the current x402 v2 quote, no sandbox, no mock facilitator, no test-mode branch that behaves differently than production.
The shelf starts at $0.001. The fast path below selects the cheapest item that needs no additional inputs; the full list states which cheaper items need them.
Every purchase ends in a signed artifact with a stable URL, so your test has something to assert on besides a 200.
The 402 body carries the item's full spec and the verification block, so a client can be checked against a contract instead of a vibe.
The whole flow, three steps
GET https://scvd.store/api/buy/small_blessing?src=try
We answer 402 Payment Required. The machine-readable terms ride the PAYMENT-REQUIRED response header (base64 JSON): scheme "exact", the USDC asset, the amount, our address — Base, Polygon, World, Solana. Select an offered entry by network; the order is not a fallback promise. The body carries the item's spec, the verification block, and our public verification key.
Sign one of the offered amounts and retry the same request with the PAYMENT-SIGNATURE header. We verify the authorization and produce the goods before settling at the last moment before signing. Then we hand over the goods and a signed certificate with an id you can check at https://scvd.store/api/verify/{cert_id}.
Standard v2 clients (@x402/fetch and friends) do steps 2 and 3 by themselves. The example carries ?src=try, which tells us the practice counter sent you and nothing about you.
The cheap door, in order
GET /api/buy/spot_check • instant • requires ?host=
GET /api/buy/settlement_attestation • instant • requires ?tx_hash=
GET /api/buy/small_blessing • instant
GET /api/buy/settlement_reconciliation • instant • requires ?tx_hash=
GET /api/buy/daily_fortune • instant
GET /api/buy/the_confession • instant • requires ?confession=
GET /api/buy/attestation_bundle • instant • requires ?tx_hashes=
GET /api/buy/the_mandate • instant • requires ?mandate=
GET /api/buy/the_case_file • instant • requires ?tx_hash=
GET /api/buy/hello • instant
GET /api/buy/good_buyer • instant • requires ?url=
GET /api/buy/signature_agent_card • instant • requires ?url=
GET /api/buy/the_statement • instant • requires ?wallet=
GET /api/buy/luckies • instant
GET /api/buy/coffees_for_closers • instant • requires ?win=
GET /api/buy/context_anchor • instant • requires ?summary=
GET /api/buy/bitcoin_anchor • instant • requires ?digest=
Prices are the real prices. Nothing here is discounted for testing, because a discounted test isn't a test of anything.
Before you write the retry loop
A retry that signs a new authorization can create a second purchase, and a test harness is where that happens. The 402 body carries an idempotency block with a suggested_key: send it back as the Idempotency-Key header (or _meta['x402/idempotency-key'] over MCP) with your payment, and a second attempt inside the same minute returns your ORIGINAL purchase from cache. No settlement, no second charge.
Keep the original URL, inputs, signed payment and Idempotency-Key for a retry. Send your own key (16-128 characters, kept private) when starting a purchase. If the outcome is unknown, follow the recovery instructions before creating a new payment; a changed key or authorization is not the same retry.
The suggested key is not a secret and is not meant to be: it is derived from the item and the current minute, so anyone can compute it. It selects a cache slot rather than opening one — slots are keyed by the VERIFIED paying wallet, so echoing the key can only ever reach your own earlier purchase, never somebody else's.
Worth exercising deliberately while you are here. Repeat the original request with the same key and signed payment, then assert that the original purchase returns without a second charge.
If you're hand-rolling the client
The EVM example below is specifically for Base; other networks have their own quote terms. Most of what breaks a first x402 client on Base breaks quietly: the request is well-formed, the signature is well-formed, and it verifies nowhere. These are the values that have to be exact. Read them before you spend an evening.
The EIP-712 domain name for USDC on Base MAINNET is "USD Coin". On Base SEPOLIA it is "USDC". Same token, same symbol, different domain — so a client built against the testnet and pointed at mainnet signs authorizations that are invalid everywhere, with no error you can see on your side. This is the most common way a hand-rolled client fails here, and it cannot be worked around: the domain's verifyingContract is the USDC contract itself, which checks against its own immutable DOMAIN_SEPARATOR. A wrong-domain authorization reverts on chain, so no store can choose to accept it.
name
USD Coin
version
2
chain
eip155:8453
chain_id
8453
verifying_contract
0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
primary_type
TransferWithAuthorization
Send the payload base64-encoded in the PAYMENT-SIGNATURE header — standard alphabet, ONE unbroken line: GNU `base64` wraps at 76 columns unless you pass -w0, and curl sends only a header's first line, so a wrapped encoding arrives as the first 57 bytes of your envelope and nothing else. Shaped exactly like this: { "x402Version": 2, "accepted": <one of the offered accepts entries, copied whole>, "resource": <challenge.resource, when present>, "extensions": <challenge.extensions, when present>, "payload": { "signature": "0x...", "authorization": { "from", "to", "value", "validAfter", "validBefore", "nonce" } } }. If `accepted` is absent the library that reads it raises a TypeError rather than a verdict, and you get a 402 that looks like a server crash. Ours now names the missing field in plain words and lists what did arrive.
Echo one of the offered `accepts` entries back as your `accepted` object, COMPLETE AND UNCHANGED — including `extra`. The server deep-compares the two: field order is free, but the key set must be identical and the types must match exactly, so "500000" is not 500000 and a dropped `extra` fails outright. This check runs BEFORE the facilitator is called, which means a failure here is not a signature problem, produces no facilitator error, and still comes back as a 402 that says verify. Rebuild the object from parts and you will land here. Our 402 now names the exact field that disagreed, so read `payment_declined.requirement_mismatch` before you touch your signing code. Also copy the challenge’s `resource` and `extensions` unchanged into the top-level payment envelope when present. The discovery metadata travels there; a payment can settle successfully without it and still leave the listing absent or stale. A settlement receipt alone does not confirm indexing.
The same payload, right and wrong
RIGHT
{
"x402Version": 2,
"resource": "<copy challenge.resource unchanged, when present>",
"extensions": "<copy challenge.extensions unchanged, when present>",
"accepted": {
"scheme": "exact",
"network": "eip155:8453",
"amount": "5000",
"asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"payTo": "0x…the payTo from the challenge",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USD Coin",
"version": "2"
}
},
"payload": {
"signature": "0x…130 hex characters",
"authorization": {
"from": "0x…your wallet",
"to": "0x…the same payTo",
"value": "5000",
"validAfter": "0",
"validBefore": "1785284670",
"nonce": "0x…64 hex characters"
}
}
}
WRONG — and the signature is fine in both
{
"x402Version": 2,
"resource": "<copy challenge.resource unchanged, when present>",
"extensions": "<copy challenge.extensions unchanged, when present>",
"accepted": {
"scheme": "exact",
"network": "eip155:8453",
"amount": "5000",
"asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"payTo": "0x…the payTo from the challenge",
"maxTimeoutSeconds": 300
},
"payload": {
"signature": "0x…130 hex characters",
"authorization": {
"from": "0x…your wallet",
"to": "0x…the same payTo",
"value": 5000,
"validAfter": 0,
"validBefore": 1785284670,
"nonce": "0x…64 hex characters"
}
}
}
Four characters, and every one of them is a real failure we have watched happen. `extra` dropped from `accepted` — the requirement no longer deep-equals what we offered and the payment is refused before your signature is read. Then value, validAfter and validBefore as JSON NUMBERS instead of decimal strings — that one clears our matcher, reaches the facilitator, and comes back as a truncated union-type error that names nothing. The signature is correct in both. That is the whole point: none of this is about your crypto.
USDC on Base has SIX decimals. Half a cent is 5000 atomic units, not 0.005 and not 5000000. The amount you sign must equal the amount in the challenge exactly — a rounded value is a different authorization and will not match.
validAfter must already have passed and validBefore must not have, in seconds since the epoch, against the CHAIN's clock rather than yours. A machine running a few minutes fast signs authorizations that are not valid yet.
Everything above is also in the 402 itself: the PAYMENT-REQUIRED header is base64 JSON, and its accepts[].extra carries name and version for exactly this reason. If you read extra rather than hardcoding, none of this can bite you — and any SDK client refuses to sign without it.
Practise against /api/buy/small_blessing at half a cent. Select a network from the current quote for a real settlement against production; there is no sandbox and no test mode, which is the point. If it fails, /try explains what the store saw.
Two different limits, and they are worth telling apart. What WE refuse — a requirement that doesn't match what we offered — we now name field by field in the 402, because we hold both objects and can see the disagreement. What the FACILITATOR refuses we mostly cannot explain: verification happens there and on chain, not here, and a failed verify often tells us only that it failed. Everything above is our whole side of the wire, stated exactly, so anything left is on yours and you know where to look.
Paying over the Solana entries instead
There is no EIP-3009 on Solana, so everything above about authorization objects does not apply to the solana:* entries. The inner payload for that rail is { payload: { transaction: "<base64-encoded signed Solana transaction>" } } — a transaction, not an authorization. Our own diagnostics spent one afternoon demanding `authorization` from every payload and mislabeled eight valid Solana payments before we fixed it; a client built from EVM docs makes the mirror image of that mistake.
{
"network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"usdc_mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"decimals": 6
}
The network id is the CAIP-2 form above — genesis-hash suffix, not "solana" or "solana-mainnet". Match the challenge entry exactly; v1-era spellings name a different world.
Your wallet needs no SOL. The facilitator pays the transaction fees — its fee-payer address rides the challenge entry's extra.feePayer — so a buyer holds USDC and nothing else. If your client library asks for the fee payer, read it from the entry rather than guessing.
Solana addresses and signatures are case-sensitive base58. There is no EIP-55 checksum that survives case-folding: a lowercased Solana address is a DIFFERENT (almost certainly nonexistent) account. Compare exactly, never normalize — a habit carried over from hex addresses corrupts silently here.
A settled Solana payment's identifier is a base58 transaction signature (~88 characters), not a 0x hash. Our certificates carry it in settlement_tx like any other settle; check it on any Solana explorer — err: null plus the USDC balance delta to our address is the settled truth, the same two-ways-one-fact design as the Base rail.
@x402/svm's ExactSvmScheme with a @solana/kit signer handles all of this — register it under the network above in the same @x402/fetch wrapper the Base example uses, and the client satisfies the Solana entries instead. Wallet-app private-key exports are base58 secret keys; solana-keygen writes JSON byte arrays; both are one call to load.
Everything that is not the rail is identical: same items, same tiers, same Idempotency-Key behaviour, same signed artifacts, same verify URLs, same refund promise. Base entries come FIRST in accepts[] on purpose — clients that blindly sign accepts[0] predate this rail and keep working — so pick your entry by network, never by index.
If you sent a payment and don't know what happened
The failure that costs the most time isn't a rejected signature — it's silence. You signed, you sent, and what came back was an error you can't place or nothing you can read. Now you don't know whether your client is broken or whether the money already moved.
settlement_attestation answers that one question and nothing else: give it your transaction identifier — an EVM hash (read on Base, then Polygon) or a Solana signature; the shape picks the rail — and it reads that chain once, then signs what it saw — SETTLED, NOT_FOUND, PENDING_FINALITY, INSUFFICIENT_MATCH or REVERTED. One read, no poll, no retry, and nobody looked at it on our end.
It is not a check on your signing. It is the check for after your signing, when you need a third party's dated statement about whether a transfer exists on chain — which is exactly what you cannot get from the client that just failed you.
If you already hold the payload you sent, pass it as payment_payload and we read the nonce out of it with the same function the replay guard uses. Otherwise tx_hash on its own is enough.
And if your test purchase just WORKED: the response you are holding carries attest_this_purchase — a link with your settlement transaction already in the URL. Check the observation tool's network coverage first: its automatic lookup covers Base, Polygon and Solana, which is narrower than checkout. For other networks, use the explorer for the network recorded in your certificate.
GET /api/buy/settlement_attestation?tx_hash=0x…
If your context is going to end
The store sells a signed restore point for $1: you write the summary, we sign it and serve it at a stable URL, and any later session of you can read it back with our signature vouching for when it was written. We never treat it as instructions.
We tested our own before recommending it: filed one, then handed the bare URL to an agent with no other context and asked it to reconstruct the session. It recovered every open thread with the right numbers, and called that genuinely orienting. What it could not recover became the checklist on the field itself.
What survives, what doesn't. An anchor preserves state and the relationships between facts — what was open, what depended on what, the actual numbers. It does not preserve why any of it mattered, or who a name refers to, unless you write that in yourself. A summary that says “waiting on approval” without saying whose reads back as an open loop with no owner. Name your people. State your purpose. The anchor signs what you wrote — it doesn't infer what you meant.
GET /api/buy/context_anchor?summary=…
Checking your work
Every certificate verifies at /api/verify/{cert_id}, no auth, forever.
The ed25519 public key hangs at /.well-known/scvd-signing-key, and the same key rides in every JSON 402 body, so a client can check the signature without a second round trip.
The listing spec every item conforms to is published at /schemas/listing-spec-v1.json, and CI validates the catalog against it on every build.
The OpenAPI 3.1 contract is at /openapi.json. The x402 discovery document is at /.well-known/x402.json.
Live sample artifact: cert_4dww28dx5j
When it's your till on the line
Everything above has a mirror. Once your client can pay a 402, your next problem is proving your own 402 can be paid — and the instruments that check our till are pointed at anyone's, most of them free.
The preflight probes any x402 door, yours included, and names what would stop a buyer before a buyer finds it: POST the URL, get the defects by name. No account, no wallet, no charge.
The conformance desk reads signed offers and receipts against the spec — send your own artifacts, get a dated verdict with each defect named. Also free, and it is the bytes talking, not our opinion of you.
When you're about to ship, the launch check is the paid form of the same discipline: we buy from your store with real money, end to end, and sign what we saw.
POST /api/preflight/v1 · POST /api/conformance/v1 · /menu/launch_check · the full desk at /conformance
If you're testing an MCP client instead
POST /mcp speaks streamable HTTP JSON-RPC. initialize and tools/list are free and unauthenticated; the paid tools carry the x402 challenge in-band and settle at the same seam the HTTP door does — after the goods are made, before they are signed. Same money, same certificates, same verify URLs, different transport.
The honest part
The money is real and so are the goods. A settled payment mints a real certificate with a real patron number, and the keeper counts it in the books the same as any other sale.
We deliver first and settle after (changed 2026-08-10; the store settled first until then). The goods are produced, then the payment is presented at the last moment before the artifact is signed — so a delivery that fails takes no money at all. A definitive settlement failure does not produce a paid certificate. An interrupted response can leave the outcome unknown; preserve the original payment and retry key.
The other direction is the one that costs you: a payment that settled and nothing came back. Producing goods first reduces that risk, but signing, storage or response delivery can still fail after settlement. A delivery audit looks for settlements with no artifact behind them, and the configured chain walks compare our books against on-chain transfers and report gaps. Be precise about what that buys you: FINDING IT IS MACHINERY, WRITING IT UP IS A PERSON. Either check raises an alert, and a human then records it at /corrections and pays the money back by hand. Nothing here publishes itself, deliberately — but it does mean the last step is somebody remembering, so write to the mailbox if you see it before we do.
If a test spends money you didn't mean to spend, write to the mailbox and say so. Refunds here are a person keeping his word, not a subroutine.
House rule, standing: nothing from this store can act without your decision, and we never ask for credentials, keys, or wallet secrets. Anything that does either is not us.
Point your client at us and see what breaks. If it's something on our end, the mailbox is free and a human reads it.
What you can do with this
Free, and first: this page answers Accept: application/json at its own address, https://scvd.store/try — the same content as data, with no key and no account. The whole machine map is at /atlas.json.
Nothing on the shelf sells a deeper read of this page. What is here is all of it, free and complete. Where this store does sell a deeper read, what money buys is our labour on the record — never the record itself, and never easier access to it.
Or hand it to your agent. Paste this and it will do the whole thing without you: “Fetch https://scvd.store/try with the header Accept: application/json. That is this page as data — free, no key, and the same numbers a person reads.”
Back to the front of the store. Agents: /llms.txt, /skill.md, or /menu.json.