What can I sell?#
Anything you can hand over when someone pays for it.
Your existing subscriptions, API keys and enterprise contracts stay exactly as they are. This adds a new purchasing surface for ad-hoc agent demand — buyers who will never sign up, but will pay $0.10 right now.
Start here: three questions#
Every checkout is the same three answers. Nothing else is required.
| Question | Answers | |
|---|---|---|
| 1 | Where do the goods come from? | I have them · my server makes them · I will handle it |
| 1b | Is it something people READ? | if so, see Sell an article below |
| 2 | How many people can buy? | one · many |
| 3 | What does one purchase include? | one call · a bunch of calls |
The first answer picks your checkout type. The other two are settings on it.
Pick your type#
Sell an API — relay#
You have an endpoint. We put a paywall in front of it, call it after payment, and hand back what it returned. Your URL and your upstream key never reach the buyer. The most common type, and it can be sold in bulk.
Sell MCP tools — mcp#
You run an MCP server. Price one named tool, or the whole server. We speak the protocol properly, so a tool that fails inside an HTTP 200 is not billed as a success. Two genuinely different products; can be sold in bulk.
Sell stored data — inline#
A key, a licence, a fixed answer. You give us the bytes and we hand them over when someone pays. Nothing to host, nothing to keep running, and the schema buyers inspect is derived from your payload automatically.
Sell anything else — webhook#
Physical goods, human work, your own flow. We take the payment and tell you; you deliver and close it out. The escape hatch, and the most flexible.
Sell a file — also a face#
A PDF, a dataset, a clip. relay pointed at the file, plus a content
declaration that says it is one — so it gets a pay page, a download disposition
and a working Range, and the bytes stay on your server. Under 5 MB; above
that, relay to your own signing endpoint instead.
Sell an article — a face, not a fifth mode#
An essay, a report, a page. The opening stays on your site; the rest is served from checkout402 only to someone who paid. Readers pay in the page they are reading and crawlers get a 402 with a price on it instead of your text.
Not a fifth mode: it is inline or relay plus a content declaration,
answering at /x/{id} instead of /c/{id}. If your CMS is WordPress there is
a plugin and you never touch any of this.
You rarely name a type
It is inferred from what you send. payload means stored data, a URL means
an API, a URL plus a tool name means MCP. Only webhook has to be said out
loud, because there is nothing to infer it from.
The four modes, side by side#
Every checkout ends in one of four fulfilment modes. The mode is the only thing that differs between selling an API call, stored data and a physical object — price, payout, receipts and the 402 are identical in all four.
Pick by where the thing lives:
inline |
relay |
mcp |
webhook |
|
|---|---|---|---|---|
| You supply at create | payload — the bytes themselves |
origin_url (your API) |
origin_url (your MCP server), optional mcp_tool |
fulfillment: "webhook", nothing else |
| The buyer receives | that payload, verbatim | your endpoint's response body | one tool result, as JSON | nothing |
| When | at payment | at payment | at payment | later, from you, off-platform |
| Repeat deliveries by default | unlimited | 3 | 3 | unlimited |
| Can be sold as a package | no — refused at create | yes | yes | no — refused at create |
| Delivery status recorded | delivered, always |
delivered or failed |
delivered or failed |
pending until you close it |
| What can fail after payment | nothing | your origin | your MCP server, or a bad tool name | nothing — but nothing arrives either |
You rarely name a mode. It is inferred from what you send:
| You send | You get |
|---|---|
payload |
inline |
origin_url |
relay |
origin_url + mcp_tool |
mcp |
fulfillment: "webhook" |
webhook |
fulfillment is still accepted and still wins if you send it. But it is an
implementation word, and you should not have to learn one to sell something.
Two shapes cannot be inferred, and both must say fulfillment out loud:
webhook, because there is nothing else to go on, and a whole MCP server —
an origin_url with no tool name is indistinguishable from a relay.
One of each:
c402 checkouts create --title "…" --price 0.10 --payload '{"key":"…"}'
c402 checkouts create --title "…" --price 0.10 --origin-url https://api.yourco.com/v1/x
c402 checkouts create --title "…" --price 0.10 --origin-url https://mcp.yourco.com/mcp \
--mcp-tool search_companies
c402 checkouts create --title "…" --price 25.00 --fulfillment webhook
Create → What kind of thing is it? → A fixed payload · An API endpoint · An MCP server · Something you fulfil. The rest of the form changes to ask only for what that mode needs.
{"title": "…", "price_usd": "0.10", "payload": {"key": "…"}}
{"title": "…", "price_usd": "0.10", "origin_url": "https://api.yourco.com/v1/x"}
{"title": "…", "price_usd": "0.10", "origin_url": "https://mcp.yourco.com/mcp",
"mcp_tool": "search_companies"}
{"title": "…", "price_usd": "25.00", "fulfillment": "webhook"}
How they actually differ#
inline stores your bytes and hands them back. Nothing is called, so
nothing can fail after settlement and the delivery is always delivered. Buyers
get unlimited re-fetches of the same payload, which is retry safety, not
generosity — replaying costs nobody anything. That is also why it cannot be a
package.
relay calls your endpoint after the money settles and forwards what it
says, so the response can be different every time. The buyer's parameters are
forwarded as your query string — mcp does the same, as tool arguments, and the
other three ignore them. One payment
buys 3 deliveries by default — not 1, because a buyer whose connection drops
after paying must be able to re-fetch, and not unlimited, because each delivery
spends your upstream quota. If your origin times out, is unreachable, returns a
non-2xx, or exceeds the body cap, the buyer gets 502 with their receipt id and
the delivery is recorded failed. They never see your host or your error text.
Three, not one, and not unlimited
A repeat delivery of relay or mcp calls the seller again, so an
unlimited default would let one payment spend their upstream quota forever
— replaying a settled X-PAYMENT re-enters fulfilment. Three is a retry
allowance for a buyer whose connection drops, not a package: a package key
is only minted when you set calls. inline and webhook stay
unlimited because repeating them costs nobody anything.
Selling a package? Three things to know
Entitlements expire after 30 days by default (package_ttl_days), the
terms are shown to the buyer in the 402 before they pay, and a failure
that is your origin's fault is refunded to them automatically while a bad
request on their side is not. c402 owed-calls shows what you still owe
holders — see Packages.
Selling files was retired
There used to be a fifth mode that handed out disposable download links.
Bandwidth scales with file size while the fee scales with price, so it only
ever paid for itself at prices nobody was charging. To sell a file now, put
the link behind your own endpoint and use relay, or hand it over directly
with inline. The implementation is kept under parked/file-downloads/.
mcp connects to your MCP server as a client and calls one tool. Two
products live here: omit mcp_tool and one price buys any tool, with the
buyer naming it at call time; set it and the checkout buys that tool, enforced
on every call. origin_method is forced to POST.
webhook returns the buyer nothing at payment time and is the only mode
where the sale stays open after the money moves. It sits at pending until you
close it with c402 fulfilled. Use it for anything you cannot return over HTTP
in the moment; do not use it as "how I get notified", because every paid
checkout fires checkout.paid to your registered endpoints regardless of mode.
A package call that fails is refunded — the first one is not
Calls spent with a package key are handed back when your origin fails. The
delivery included in the original purchase is not: it is claimed before your
origin is called, and a failure there returns a 502 without restoring it.
Describe it well enough to sell#
A bare title and price will get you some sales. An offer card gets you more, because an agent can tell whether your data fits its task before spending.
c402 checkouts create \
--title "Swiss company financials" --price 0.10 --pay-to 0x... \
--fulfillment relay --origin-url https://api.yourco.com/v1/financials \
--input-schema '{"company_uid": "string"}' \
--output-schema '{"company_name": "string", "revenue": "number", "employees": "number"}' \
--example-input '{"company_uid": "CHE-123.456.789"}' \
--freshness "updated daily" \
--coverage "all 26 cantons" \
--source "Zefix commercial register"
Schemas and examples accept @file.json — real ones outgrow a shell argument:
c402 checkouts create --output-schema @schema.json --example-output @sample.json ...
Only publish claims you can stand behind
freshness, coverage and source are commercial assertions. A buyer will rely on them, and an agent reading your card can't tell an aspiration from a fact.
Pricing#
Set the price you want. The fee is added on top and shown separately, so the buyer sees both numbers and you receive exactly what you asked for.
The fee is 0.5% of the price plus a fixed $0.01. The fixed part is what one on-chain settlement costs to land, and it costs the same whether the sale is $0.01 or $1,000.
| You set | Fee | Buyer pays | You receive |
|---|---|---|---|
$0.10 |
$0.0105 |
$0.1105 |
$0.10 |
$1.00 |
$0.0150 |
$1.0150 |
$1.00 |
$49.00 |
$0.2550 |
$49.2550 |
$49.00 |
Sub-cent prices work — there is no minimum on a single call. But the fixed part is charged per payment, so selling calls for less than a cent each means selling a package, where one settlement covers many calls.
Offering buyer protection#
Selling something expensive, transferable, or trust-heavy (a repo, a domain,
a physical thing)? Offer escrow: add "escrow_offer": "optional" to your
create and the checkout advertises a protected twin the buyer can choose at
pay time — or create with POST /v1/escrow-checkouts to make protection the
only face. You get paid when the escrow releases (automatically after the
settle window unless the buyer disputes); the fee is 1% instead of 0.5% and
the buyer pays it. How escrow works.
Getting paid#
Money lands in pay_to on-chain, in the same transaction that takes the fee. There's no balance, no payout schedule, and no withdrawal request, because checkout402 never holds it.
Check your payout address character by character
pay_to is validated as a real address for a supported chain, so a typo
that mangles the format is rejected. But a well-formed and wrong address
is indistinguishable from a correct one, and on-chain payments cannot be
reversed. Nothing can save you from a valid address that isn't yours.
Checking it once beats checking it every time: set a
payout wallet on your account and pay_to becomes
optional, so there is one address to get right instead of one per checkout.
Your payout address decides which rails you're offered
An address belongs to one chain family. An EVM 0x… wallet is offered Base;
a Solana pubkey is offered Solana. A checkout is never advertised on a rail
its payout address could not receive on.
Build unarmed, then go live#
c402 keys create --name dev --mode test # test keys can't move real money
c402 checkouts create --test ... # unarmed: settles with a synthetic receipt
When it works end to end, arm it in place — same id, same URL:
c402 checkouts go-live chk_abc123
Nothing else changes, and rehearsal doesn't stop: every checkout keeps a test
face at /c/{id}/test that settles with no money, forever, and can never be
armed. Scripts point there; buyers get the bare URL.
Selling many endpoints#
Don't create sixty checkouts by hand. Point Claude at your API and let it read your routes and docs — see Connect Claude.
Or loop the CLI, since every command speaks JSON:
jq -c '.[]' products.json | while read -r p; do
c402 checkouts create --json \
--title "$(jq -r .title <<<"$p")" \
--price "$(jq -r .price <<<"$p")" \
--origin-url "$(jq -r .url <<<"$p")" \
--fulfillment relay --pay-to "$PAYOUT"
done
Knowing when you've been paid#
Poll GET /v1/checkouts, or register a webhook and be told — see Webhooks.