Concepts#
checkout402 has one object. Understanding it is most of understanding the product.
The Checkout#
A checkout is { price, payTo, what-you-get } — a URL with two faces.
Checkout = Offer + Payment + Fulfilment
| Part | What it means |
|---|---|
| Offer | What's for sale, described well enough that an agent can decide before paying |
| Payment | The price, the fee, and which rails you accept |
| Fulfilment | What the buyer actually receives once money moves |
There is no separate "product", "listing", or "catalogue" object. Deliberately: creating a checkout should not feel like creating a marketplace listing.
Two faces, one URL#
GET /c/chk_abc123 content-negotiates:
Accept |
You get |
|---|---|
text/html |
A pay page — price, description, a wallet button |
| anything else | HTTP 402 with accepts[], the fee split, and the offer card |
Same object, same price, same ID. The buyer's client decides which face makes sense.
The offer card#
The optional metadata that makes an unpaid 402 genuinely useful. All fields are optional — creating a checkout stays fast — but each one raises the chance an agent completes the purchase.
| Field | Answers |
|---|---|
title, description |
What is this? (required) |
input_schema |
What do I provide? |
output_schema |
What will I get back? |
example_input, example_output |
Can I see it before paying? |
freshness, coverage, source |
Is it suitable for my task? |
constraints |
What are the limits? |
These are commercial claims
freshness, coverage and source are assertions a buyer will rely on. If an agent fills them in on your behalf, it should propose them for your approval — not publish them as fact.
Fulfilment modes#
What happens after settlement. Money moves first, always.
| Mode | Behaviour | Use when |
|---|---|---|
inline |
Returns payload verbatim |
You're selling a key, a file, a fixed answer |
relay |
Calls your origin_url, forwards the response |
You're putting an existing API behind a paywall |
webhook |
Receipt only; you're notified async | Fulfilment happens in your own system |
Settle-before-deliver is not configurable
The ordering — verify, settle, then release — isn't a setting. The opposite ordering isn't representable in the code.
Payments and receipts#
Every payment attempt writes a CheckoutPayment row with its own pay_… id, addressable at /r/pay_….
A receipt carries the payer, the seller, the exact split, the network, the transaction hash, and the delivery outcome. Two faces again: JSON for agents, HTML for humans.
The X-PAYMENT-RECEIPT header returns it inline on the paying request, so an agent gets its receipt in the same round trip as the goods.
Retrying is safe
Re-presenting the same X-PAYMENT redelivers the goods and never charges twice. A dropped connection after settlement is the worst failure in payments — the buyer has paid and has nothing — so the same signed authorization is idempotent by design.
Single-shot vs reusable#
| Behaviour | |
|---|---|
| Default | One payment, then status: paid. An invoice. |
reusable: true |
Many payments, stays open. A payment link or a metered endpoint. |
Test mode#
A test_mode checkout settles without touching a chain — synthetic 0xtest_… hash, test_mode: true stamped on the payment and the receipt.
It's gated by the checkout row, which only its seller controls, and a c402_live_ key cannot create one. So it's never silently reachable from a live checkout.
The fee#
0.5% of the price, plus $0.01. Visible in the 402 before anyone pays, and split out on-chain in the same transaction that pays you.
Your price $0.10
Fee $0.0105 (0.5% of $0.10 = $0.0005, plus the $0.01 fixed part)
Buyer pays $0.1105
You receive $0.10 — always your full price
On Base the split runs through an immutable splitter contract. On Solana there's no contract at all — the split is two SPL transfers inside the buyer's own transaction. Either way, checkout402 never holds the money.
Identity#
| Who | How | Why |
|---|---|---|
| Buyers | Nothing. The payment is the login. | No signup is the entire point |
| Sellers (human) | Magic link → session cookie | No password to leak |
| Sellers (agent) | Wallet signature → automation key | Agents have keys, not inboxes |
A signed wallet challenge is a verified identity here — bring-your-own-wallet is the product thesis, and the signature proves control of the payout address.
The fixed $0.01 is one on-chain settlement, not margin — it costs real money to land a transaction, and it costs the same whether the sale is $0.01 or $1,000. That is also why packages exist: a package settles once and serves many calls, so a $1 package of 1,000 calls pays the fixed part once instead of a thousand times. Selling calls for less than a cent each is a package, not a cheaper single call.
Single calls have no minimum price, deliberately. A cheap one is how a buyer tries your API before committing — $0.015 to find out, rather than $1.01.