Skip to main content

Quickstart: get paid

Put an x402 paywall in front of your API and take the first paid call in five minutes.

1 min read
View MarkdownEdit on GitHub

Quickstart: get paid

You have an endpoint. Agents want to call it. This guide puts Gate, the x402 gateway, in front of it: an unpaid call gets an HTTP 402, a paid call settles USDC to a wallet you choose and is proxied to your backend with a sealed receipt. The caller creates no account, holds no card, opens no session. Gate is live on Base mainnet.

Four steps: create a paywall, read the 402 with your own eyes, pay it, read the earnings.

Prerequisites

  • A CodeSpar API key with the admin role. Mint one at Dashboard → API Keys. A csk_test_ key creates paywalls that settle on Base Sepolia; a csk_live_ key settles real USDC on Base mainnet.
  • A public https endpoint to charge for. The gateway fetches it server-side on every paid call, so localhost and private hosts are rejected at create time.
  • For step 3, something that can pay: the CodeSpar CLI (shown below) or any x402 v2 client such as @x402/fetch or an agent on the CDP Bazaar.

No endpoint handy? curl -i https://gw.codespar.dev/e2e-live hits a permanent live paywall priced at $0.01. Every step below works against it, except that the money lands with us.

Create a paywall

One POST /v1/paywalls names your upstream, sets the price, and says where the money lands (full reference). Prefer clicking? The dashboard's Machine payments page has a create drawer with the same fields.

curl -X POST https://api.codespar.dev/v1/paywalls \
  -H "authorization: Bearer $CODESPAR_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "slug": "market-data",
    "name": "Market data API",
    "upstream_url": "https://api.yourservice.com/quote",
    "price": "0.01",
    "payto": { "kind": "provisioned" },
    "consumer_id": "you"
  }'

payto decides who gets paid, and settlement is non-custodial either way. provisioned settles into the CodeSpar-derived wallet of the consumer_id you pass, a governed wallet your own agent can later spend from. { "kind": "byo", "address": "0x..." } settles straight to an EVM address you already hold.

The 201 response carries the URL you share with the world:

{
  "id": "pw_9f81c2",
  "slug": "market-data",
  "price": "0.01",
  "currency": "USDC",
  "pricing_model": "flat",
  "gateway_url": "https://gw.codespar.dev/market-data",
  "active": true
}

Flat pricing is the default. Tiered price curves and dynamic per-request pricing are live too; post-paid metered pricing is in beta, see Meter. Slugs are a global namespace, and gw.codespar.dev/market-data/<path> forwards the trailing path to your upstream, so one paywall can front a whole API surface.

Curl it and read the 402

curl -i https://gw.codespar.dev/market-data
HTTP/2 402
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiZXJyb3IiOiJwYXltZW50IHJlcXVpcmVkIi...

The challenge arrives base64-encoded in the PAYMENT-REQUIRED response header; the JSON body of the 402 is only a human-readable hint. Decode the header and you get an x402 version 2 challenge:

curl -sD - -o /dev/null https://gw.codespar.dev/market-data \
  | awk 'tolower($1)=="payment-required:" {print $2}' | base64 -d
{
  "x402Version": 2,
  "error": "payment required",
  "resource": {
    "url": "https://gw.codespar.dev/market-data",
    "mimeType": "application/json",
    "description": "Market data API"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "10000",
      "payTo": "0x15cA...9E41",
      "maxTimeoutSeconds": 120,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ]
}

amount is atomic USDC (6 decimals), so 10000 is your $0.01. network follows the paywall's environment: eip155:8453 (Base mainnet) on live, eip155:84532 (Base Sepolia) on test. Nothing has reached your upstream yet, and nothing will until a payment verifies.

Pay it

An x402-capable client reads the header, signs the payment, and retries the call.

The CLI pays under a signed mandate, so the spend is capped and receipted on the buyer side too. It uses the same CODESPAR_API_KEY (run codespar login once, or export the key):

npx @codespar/cli mandate create \
  --consumer you --agent smoke-test \
  --purpose "first paid call on my own paywall" \
  --payee https://gw.codespar.dev/market-data \
  --cap 10 --per-tx-cap 1

codespar spend --mandate cm_xxx --agent smoke-test \
  --payee https://gw.codespar.dev/market-data --amount 1

CLI amounts are minor units (cents): --amount 1 pays the $0.01 challenge. The response is your upstream's 200 body; the settlement result rides back in the PAYMENT-RESPONSE header.

Any client that speaks x402 version 2 works: decode PAYMENT-REQUIRED, sign an EIP-3009 USDC authorization for amount to payTo on the advertised network, and retry with the signed payment in the PAYMENT-SIGNATURE request header (X-PAYMENT is accepted for v1 compatibility). @x402/fetch wraps this into a drop-in fetch; agents on the CDP Bazaar discover and pay 402 endpoints on their own.

Either way, the gateway verifies the signature, settles the exact amount on-chain to your payTo, seals a hash-chained receipt, and only then proxies the request to your upstream.

Read the receipt and the earnings

curl https://api.codespar.dev/v1/paywalls/pw_9f81c2/stats \
  -H "authorization: Bearer $CODESPAR_API_KEY"
{
  "paywall_id": "pw_9f81c2",
  "slug": "market-data",
  "currency": "USDC",
  "settled_count": 1,
  "gross_atomic": "10000",
  "gross": "0.01",
  "refunded_atomic": "0",
  "refunded": "0",
  "net_atomic": "10000",
  "net": "0.01",
  "last_settled_at": "2026-08-06T18:22:41Z"
}

net is what landed and stayed. On flat, tiered, and dynamic paywalls gross equals net; on a metered paywall the gap is the on-chain refund of unused ceiling, which is the feature working, not revenue lost (Meter). The same figures show inline on each paywall in Machine payments, and every settlement seals a receipt in the audit chain.

Drive it from your coding agent

The wallet a provisioned paywall settles into is a governed wallet your own agent can hold. Add the CodeSpar MCP server to the coding agent you already use:

claude mcp add codespar --env CODESPAR_API_KEY=csk_live_your_key -- npx -y @codespar/mcp serve

Then ask it "what's my wallet balance?" and watch the earnings arrive (codespar_wallet), or send them onward under a mandate (codespar_pay). Earning and spending are two halves of the same loop; the other half is the buyer quickstart.

Where to go next

Quickstart: get paid | CodeSpar