Guides
Selling
Put content or an API behind a CryptoCadet 402 and get paid per request in USDC on Base.
You need an account, the CLI, and to be signed in (cryptocadet init, then cryptocadet login). The Quickstart covers that. Seller commands only talk to the CryptoCadet server; they never touch a wallet key.
1. Claim a handle
Your handle is the public name in every item URL.
cryptocadet handle:set --handle acme
Handles are 3 to 32 characters of a-z, 0-9 and dashes, and must start and end with a letter or digit. A few names such as admin, api and cryptocadet are reserved.
2. Set your payout address
This is the Base wallet you are paid at. Use one you control.
cryptocadet payout:set --token 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 --address 0xYourBaseWallet
--token is USDC on Base. Until a payout address is set, your items accept card credits only, because a USDC payment needs somewhere to go.
3. Publish a hosted item
CryptoCadet stores the content and serves it after payment.
cryptocadet product:create \
--name "Market brief" \
--slug market-brief \
--kind hosted \
--usd 0.05 \
--content-file brief.md \
--content-type text/markdown \
--description "One-page summary for agents"
The item is now live at https://api.v4.cryptocadet.app/v4/g/acme/market-brief. The response includes it as gatewayUrl.
- Content is limited to 200 KB and is read with
GET(orHEAD). --content-typeis the MIME type it is served with. Without it, items are served as Markdown.- Slugs are 1 to 64 characters of
a-z,0-9and dashes, unique per seller. --description(up to 500 characters) is shown to buyers in the 402 response.
4. Put your API behind the gateway
A proxy item forwards each paid request to your own server, the origin.
cryptocadet product:create \
--name "Quotes API" \
--slug quotes \
--kind proxy \
--usd 0.002 \
--origin-url https://api.example.com/v1/quotes
- The origin URL must be
httpson a public host. - Any method works. A sub-path and query string are passed through:
/v4/g/acme/quotes/latest?symbol=ETHreacheshttps://api.example.com/v1/quotes/latest?symbol=ETH. - Each paid request is one charge. Requests are forwarded without the buyer's cookies or payment headers, and
Set-Cookieis dropped from your responses. - If your origin can't be reached or answers with a 5xx status, the buyer gets
502and a card-credit charge is refunded. Answer 4xx for a bad request instead, and the charge stands.
Pricing and visibility
Set the price in dollars with --usd (up to six decimal places, so 0.000001 is the smallest price) or in micro-dollars with --price. --visibility is one of:
| Visibility | Who can read it |
|---|---|
paid | Anyone who pays. The default. |
free | Anyone, without paying. Use --usd 0. |
private | Only people you share it with, paying with card credits. See below. |
Manage items with product:list, product:update --id <id> --name … or --price <micro-dollars>, and product:disable --id <id>, which takes the item offline.
Private sharing
Create the item with --visibility private, then share it with a buyer's email. Refer to the item by its slug or its id from cryptocadet product:list.
cryptocadet share:add --item checklist --email buyer@example.com --mode unlock
cryptocadet share:list --item checklist
cryptocadet share:revoke --item checklist --id <grant id>
--mode is unlock (they pay once, then read free) or per_query (they pay every time, the default). The buyer pays with an agent token on the CryptoCadet account registered to that email. Over HTTP, the same calls are POST/GET /v4/products/<id>/grants and DELETE /v4/products/<id>/grants/<grantId>, authenticated with your API key (see Your API key).
Your API key
For direct HTTP calls you need your account's API key. Sign in to cryptocadet.app/v4/api-key to reveal and copy it, or run cryptocadet api-key after cryptocadet login. Send it as Authorization: Bearer <key>, and keep it secret: anyone with it can act as your account. The CLI commands above use it for you, so most sellers never need it.
Verify requests came through CryptoCadet
Every request the gateway forwards to your origin carries these headers:
| Header | Value |
|---|---|
X-CryptoCadet-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
X-CryptoCadet-Charge | The charge id, or free for a free item |
X-CryptoCadet-Buyer | A label for the buyer, the same one shown in your sale emails |
X-CryptoCadet-Product | The item's slug |
v1 is HMAC-SHA256, keyed with your origin secret, over <t>.<charge>.<METHOD>.<path and query>, where the path and query are those of the request your origin receives. Get your origin secret (it is created on first read):
cryptocadet origin-secret
cryptocadet origin-secret --rotate replaces it; the old secret stops matching at once. Over HTTP: GET /v4/accounts/me/origin-secret and POST /v4/accounts/me/origin-secret/rotate with your API key. A Node.js check:
import { createHmac, timingSafeEqual } from "node:crypto";
// secret: your origin secret (starts with ccs_). Keep it server-side.
export function isFromCryptoCadet(req, secret) {
const sig = String(req.headers["x-cryptocadet-signature"] ?? "");
const parts = Object.fromEntries(sig.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
// Your choice: refuse signatures older than 5 minutes.
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const charge = String(req.headers["x-cryptocadet-charge"] ?? "");
// req.url is the path and query string exactly as your server received it.
const payload = `${t}.${charge}.${req.method.toUpperCase()}.${req.url}`;
const expected = createHmac("sha256", secret).update(payload).digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}
What you receive, and when
CryptoCadet keeps a 3% fee on each paid request. You receive the other 97%:
| Buyer paid with | You receive |
|---|---|
| USDC | 97% in USDC, sent to your payout wallet by the CryptoCadetRouter in the buyer's own transaction. |
| Card credits | 97% added to your earnings balance, paid out in USDC on Base to your payout address once it reaches $10. |
cryptocadet credits:show shows your earnings balance and recent entries.
Emails you get
- A sale: on every paid request, with the price, the fee, what you earn, and how the buyer paid.
- Payout sent: the amount, the wallet, and a link to the transaction on Basescan.
- Payout delayed: if a payout couldn't be sent. Your earnings are kept and the payout is retried.
They go to the email address on your account.