This walks through building a real x402 endpoint from nothing — the payment-required response, verifying a payment, and the manifest that makes it discoverable. The example targets Cloudflare Workers (matching Agent Bazaar's own stack), but the logic translates directly to any HTTP framework.
Step 1: the unpaid response
When a request arrives with no valid payment proof, respond 402 with your accepts[]:
const PRICE_USDC_BASE_UNITS = '10000'; // $0.01, 6 decimals
const PAY_TO = '0xYourWalletAddressHere';
const USDC_ON_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
function paymentRequiredResponse() {
return new Response(JSON.stringify({
x402Version: 2,
accepts: [{
scheme: 'exact',
network: 'eip155:8453', // Base
payTo: PAY_TO,
asset: USDC_ON_BASE,
amount: PRICE_USDC_BASE_UNITS,
maxTimeoutSeconds: 120,
}],
}), { status: 402, headers: { 'content-type': 'application/json' } });
}Step 2: verifying a payment
When a request arrives with a PAYMENT-SIGNATURE header, verify it before returning the resource. The exact verification logic depends on whether you're self-verifying on-chain or routing through a facilitator:
export async function onRequestGet({ request, env }) {
const proof = request.headers.get('PAYMENT-SIGNATURE');
if (!proof) return paymentRequiredResponse();
const verified = await verifyPayment(proof, {
expectedAmount: PRICE_USDC_BASE_UNITS,
expectedPayTo: PAY_TO,
expectedAsset: USDC_ON_BASE,
});
if (!verified) return paymentRequiredResponse(); // wrong amount, expired, etc.
return new Response(JSON.stringify(await getResourceData(request)), {
headers: { 'content-type': 'application/json' },
});
}Don't hand-roll verifyPayment from scratch unless you have to. Facilitator services handle settlement verification for you (submit-and-confirm, or check a facilitator's own attestation), which removes the need to run your own RPC infrastructure and handle chain reorgs correctly. solana-x402 is a zero-dependency reference you can read end to end for exactly this logic, supporting both facilitator-routed and self-verified settlement.
Step 3: supporting multiple networks
List more than one accepts[] entry to let callers pay on whichever network they hold funds:
accepts: [
{ scheme: 'exact', network: 'solana:5eykt4Us...', payTo: SOLANA_ADDR, asset: USDC_SOLANA_MINT, amount: '10000', maxTimeoutSeconds: 120 },
{ scheme: 'exact', network: 'eip155:8453', payTo: EVM_ADDR, asset: USDC_ON_BASE, amount: '10000', maxTimeoutSeconds: 120 },
]Note that payTo can differ across networks (a Solana address and an EVM address are different formats) — that's expected and correct, not a bug.
Step 4: writing the manifest
A manifest is what makes your endpoint discoverable, not just payable. Host this JSON at /.well-known/x402.json:
{
"x402Version": 2,
"resources": [
{
"url": "https://yourapi.com/api/security-report",
"description": "On-chain risk report for a token: authority, liquidity, holder concentration.",
"accepts": [
{ "scheme": "exact", "network": "eip155:8453", "payTo": "0x...",
"asset": "0x833589...bdA02913", "amount": "10000", "maxTimeoutSeconds": 120 }
],
"outputSchema": {
"type": "object",
"properties": {
"risk_score": { "type": "number" },
"mint_authority_revoked": { "type": "boolean" }
}
}
}
]
}Step 5: list it
curl -X POST https://bazaar.saylorinnovations.com/submit \
-H "content-type: application/json" \
-d '{"manifestUrl": "https://yourapi.com/.well-known/x402.json"}'Testing before you ship
Verify the unpaid path first (confirm you get a well-formed 402 with valid accepts[]) using a plain curl — no wallet needed:
curl -i https://yourapi.com/api/security-report
Then test the full paid round trip with a small real payment before listing publicly. See How to Sell an API to AI Agents for pricing and description guidance once it's live.