Sell an API#
You have an endpoint. You want to be paid per call, by buyers you will never meet, without issuing anyone an API key.
That is a relay checkout. We put a paywall in front of your URL: the buyer
pays us, we call you, and we hand back exactly what you returned.
buyer ──pays──▶ checkout402 ──calls──▶ your endpoint
◀──your response──────┘
Your URL never reaches the buyer. Neither does your upstream credential.
Make one#
Create a checkout → An API endpoint → paste your URL and a price. Everything else has a working default.
c402 checkouts create \
--title "Company financials" \
--price 0.10 \
--origin-url https://api.yourco.com/v1/financials
Create a checkout for
https://api.yourco.com/v1/financialsat 10 cents a call.
You do not need to say "relay" — a URL with no mcp_tool is one.
curl -X POST https://api.checkout402.com/v1/checkouts \
-H "Authorization: Bearer c402_live_…" \
-H "content-type: application/json" \
-d '{"title": "Company financials",
"price_usd": "0.10",
"origin_url": "https://api.yourco.com/v1/financials"}'
You get back one URL. That URL is the product.
You did not have to name the mode
origin_url means relay. payload means inline. Adding mcp_tool means
mcp. The mode is inferred from what you send, because a seller thinks "I am
selling this for 10 cents", not "this is a relay checkout".
What the buyer experiences#
The same URL has two faces.
A human opening it in a browser gets a pay page: your title, your price, the fee broken out, and a wallet button.
An agent requesting it as JSON gets 402 Payment Required with everything
needed to pay in one round trip — then repeats the request with an X-PAYMENT
header and receives your endpoint's response.
{ "fulfillment": { "mode": "relay",
"content_type": "application/json",
"payload": { … your endpoint's body … } },
"receipt": { "id": "pay_…", "url": "https://…/r/pay_…", "tx_hash": "0x…" } }
No account, no signup, no key issued by you. The payment is the authorisation.
Passing parameters#
Buyers rarely want the same answer twice. Query parameters pass straight through to your endpoint:
GET /c/chk_abc123?symbol=ACME&year=2026
↓
GET https://api.yourco.com/v1/financials?symbol=ACME&year=2026
You can also template the path:
c402 checkouts create --title "Country profile" --price 0.05 \
--origin-url 'https://api.yourco.com/countries/{iso3}/profile'
A buyer calling ?iso3=CHE reaches /countries/CHE/profile. Placeholder values
are percent-encoded, and scheme and host can never come from a parameter —
a buyer cannot redirect the call somewhere else.
A missing placeholder is the buyer's mistake, and it is charged
If your URL has {iso3} and the buyer sends nothing, the call fails before
we ever reach you — and it still costs them a call. That is deliberate:
see who pays when a call fails.
POST endpoints#
Plenty of data APIs are POST — GraphQL, search, bulk lookup. A relay that could only GET could not wrap them.
c402 checkouts create --title "Search" --price 0.02 \
--origin-url https://api.yourco.com/search --origin-method POST
The buyer's request body arrives as the reserved body param: one JSON
string, signed with their payment like any other param, forwarded to your
origin verbatim as application/json. The 402 tells them so
(endpoint.request_body), so an agent buying a GraphQL query sends
body={"query": "{ company(uid: \"CHE-1\") { revenue } }"}
and your API receives exactly that as its POST body — the payment is bound to
that exact body, so it cannot be swapped after signing. Malformed JSON and
bodies over 8,000 characters are refused before your origin is dialled, and
charged as the buyer's own error. PUT, PATCH and DELETE origins work
the same way (DELETE carries no body).
Wrapping an endpoint that needs a key#
This is the part that makes relay worth using. Your API can answer 401 to the
entire internet; the buyer pays instead of holding a credential.
c402 checkouts create --title "Financials" --price 0.10 \
--origin-url https://api.yourco.com/v1/financials \
--origin-auth-type bearer --origin-auth-value "$UPSTREAM_KEY"
c402 origin-keys add --auth-type bearer --value "$UPSTREAM_KEY" --name prod
c402 origin-keys list # note the id
c402 checkouts create --title "…" --price 0.10 \
--origin-url https://api.yourco.com/v1/x --origin-key <key-id>
Rotate it once and every checkout using it follows:
c402 origin-keys rotate <key-id> --value "$NEW_KEY"
The credential is encrypted at rest, injected server-to-server at call time, and never appears in anything a buyer can see — not in the response, not in a header, not in an error.
The one thing to get right
Wrap an endpoint you control, at a price that covers what the call costs you. A relay checkout will happily call an expensive upstream a thousand times if a thousand people pay for it.
Selling calls in bulk#
calls: N sells N calls for one payment. One on-chain settlement, then a pk_…
key that spends a counter — no signature, no gas, no confirmation wait on any
call after the first.
c402 checkouts create --title "500 lookups" --price 25.00 \
--origin-url https://api.yourco.com/v1/financials --calls 500
| Minimum price | $1.00 when calls > 1 |
| Expiry | 30 days, --package-ttl-days to change it |
| Rate | 60 calls/minute per key by default |
Why the minimum: settling on-chain costs about a cent regardless of size. A package settles once and covers N calls, which is the only way per-call prices below a cent work at all. A single call has no minimum, deliberately — a cheap one is how a buyer tries your API before committing.
Why the rate limit: you sold 500 calls, not 500 calls per second. Without it a package is a loaded gun pointed at your own endpoint.
See Packages for the full model.
When a call fails#
Not every failure is refunded, and the rule is whose fault it was.
| Your endpoint returns | Buyer charged | Buyer sees |
|---|---|---|
5xx, timeout, unreachable |
No | 502 |
401, 403 — your credential is broken |
No | 502 |
429 — your capacity |
No | 502 |
400, 404, 422 — their request was wrong |
Yes | your own status code |
The asymmetry is the point. Refunding a bad request would make "does record X exist?" free whenever the answer is no — buyers could enumerate your dataset at no cost while your endpoint absorbed every probe, paying only for hits.
Every call is logged with counted and fault, so a buyer can always answer
"was I charged for that one, and whose fault was it" — and so can you.
You are not billed for your own outage
A seller-fault failure hands the call back to the buyer automatically. You do not have to do anything, and it does not count against your delivery record as their mistake.
Before you go live#
A relay checkout has one dependency you do not control at purchase time: your own endpoint. Two things follow.
Rehearse on the test face. Every checkout carries one at /c/{id}/test —
same product, same call to your origin, simulated settlement. Point a script at
it, confirm the response is what you expect, then share the bare URL.
c402 checkouts create --title "Financials" --price 0.10 \
--origin-url https://api.yourco.com/v1/financials # created unarmed
c402 checkouts go-live chk_abc123 # arms it — same id, same URL
Arming changes nothing about the rehearsal: the /test face keeps settling
with no money, forever, and can never be armed. Origin-backed rehearsals draw
on a daily budget (25 per checkout by default, test_delivery_daily_cap to
change it), so a rehearsal loop cannot hammer your endpoint for free.
Say what the buyer gets. An agent decides whether to buy from the offer card, and a checkout with no description is one they cannot evaluate:
c402 checkouts update chk_abc123 \
--description "Latest filed financials for a Swiss registered company" \
--freshness "daily" --coverage "all 26 cantons" --source "commercial register"
Those are commercial claims
freshness, coverage and source are assertions a buyer relies on. If an
agent is filling them in for you, it should be proposing them, not deciding
them.
Getting paid#
The money never touches us. Payment settles buyer → your wallet in one on-chain transaction, with the fee split out in the same transaction.
0.5% + $0.01, charged on top of your price. You always receive your full price.
| Your price | Buyer pays | You receive |
|---|---|---|
| $0.10 | $0.1105 | $0.10 |
| $25.00 | $25.135 | $25.00 |
Set a payout wallet per chain and every rail you can be paid on is offered: Payout wallets.
What next#
- What can I sell? — the four types side by side
- Packages — bulk calls, expiry, who pays on failure
- Payments & receipts — what settled, and proving it
- API reference — every field