CryptoCadet

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.

Terminal
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.

WarningChanging your handle changes the URL of every item you sell. Links and agents using the old URL stop working.
Your name in the 402Each item's 402 response names the seller by your handle, the same one that is in the URL. Your email address is never included.

2. Set your payout address

This is the Base wallet you are paid at. Use one you control.

Terminal
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.

Terminal
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 (or HEAD).
  • --content-type is the MIME type it is served with. Without it, items are served as Markdown.
  • Slugs are 1 to 64 characters of a-z, 0-9 and 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.

Terminal
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 https on a public host.
  • Any method works. A sub-path and query string are passed through: /v4/g/acme/quotes/latest?symbol=ETH reaches https://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-Cookie is dropped from your responses.
  • If your origin can't be reached or answers with a 5xx status, the buyer gets 502 and 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:

VisibilityWho can read it
paidAnyone who pays. The default.
freeAnyone, without paying. Use --usd 0.
privateOnly 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.

Share an item
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:

HeaderValue
X-CryptoCadet-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256>
X-CryptoCadet-ChargeThe charge id, or free for a free item
X-CryptoCadet-BuyerA label for the buyer, the same one shown in your sale emails
X-CryptoCadet-ProductThe 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):

Get your origin secret
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:

verify.js
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);
}
TipIf a reverse proxy in front of your app rewrites paths, compute the signature over the path the gateway requested, not the rewritten one.

What you receive, and when

CryptoCadet keeps a 3% fee on each paid request. You receive the other 97%:

Buyer paid withYou receive
USDC97% in USDC, sent to your payout wallet by the CryptoCadetRouter in the buyer's own transaction.
Card credits97% 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.

NoteYou are responsible for what you publish and for any taxes on what you earn.