Originally published at unlisted.sh/guide. I built Unlisted, the paid checker mentioned at the end, but everything here works by hand for free.
Your x402 endpoint returns a 402, takes payment, and works. But it isn't in the CDP Bazaar, so agents searching the catalog never find it. I hit several of these causes on my own API, so here's every one I know of, each with the symptom and the fix.
How a route gets listed
The Bazaar doesn't crawl the web for x402 endpoints. A route gets listed when a payment to it settles through CDP's facilitator and the 402 challenge carries a valid extensions.bazaar declaration. After that, CDP re-crawls it from time to time. So you need three things: a well-formed challenge, CDP as the facilitator, and at least one settled payment.
Free first step: ask the Bazaar directly
CDP's discovery API is public. Open this in your browser with your receiving wallet address:
https://api.cdp.coinbase.com/platform/v2/x402/discovery/merchant?payTo=0xYOUR_PAY_TO_ADDRESS
If your route is there, it's listed. If not, read on.
Quick triage
| What you see | Most likely cause |
|---|---|
| Nobody has paid the route yet | 1 |
| Real payments have landed, still not listed | 2, then 3 and 4 |
| Your app runs behind Render, Railway, Fly, Heroku, nginx or a load balancer | 5 |
| Some x402 clients say there are no payment options | 7 |
| Listed, but with the wrong method or no input schema | 8 |
| Listed, but showing an old price or description | 10 |
1. No payment has settled through CDP yet
Symptom: your challenge looks right, but the route has never been paid. This is the most common cause for a brand-new endpoint.
Fix: make one real, paid call to the route that settles through CDP's facilitator. A cent is enough. Then give the Bazaar time to crawl it.
2. Payments settle through a different facilitator
Symptom: you've had real, settled payments, but the route still isn't listed.
Fix: the CDP Bazaar only learns about routes from settlements that go through CDP's facilitator. If your server uses another facilitator, CDP never sees those payments. Point the route at CDP's facilitator (it needs a CDP API key), then make one more paid call.
3. extensions.bazaar is missing or malformed
Symptom: payments settle, but there's nothing for the Bazaar to index. Decode your 402 challenge, and either extensions.bazaar isn't there or it's incomplete.
Fix: declare discovery metadata on the route. In the Python SDK that's declare_discovery_extension(...) passed as the route's extensions, plus registering bazaar_resource_server_extension on the resource server. At minimum, extensions.bazaar.info.input.type must be "http" or "mcp". If you include info.output, it needs a type too.
Also check the paying side. A client that drops the extension when it sends the payment leaves CDP with nothing to index (x402 #3557).
4. The description is too long
Symptom: everything else is right, payments may even fail, and nothing tells you why. A long route description can break things without any error (x402 #2993).
Fix: keep the route's description under about 500 characters. One or two sentences is plenty: what it returns and what it costs.
5. resource.url says http:// behind a proxy
Symptom: your public URL is https://, but the decoded challenge advertises http://. Your host terminates TLS and forwards plain HTTP to your app, so the app builds the URL from what it sees. CDP's validation only accepts https:// resource URLs.
Fix: tell your server to trust the forwarded scheme. For uvicorn:
uvicorn main:app --proxy-headers --forwarded-allow-ips='*'
# or set the env var
FORWARDED_ALLOW_IPS=*
For other stacks, read X-Forwarded-Proto (Express: app.set("trust proxy", true)), or hardcode your public https base URL.
6. The resource field is missing
Symptom: the challenge has payment options but no resource, so the Bazaar doesn't know which URL it's cataloging.
Fix: include resource.url: the full public https URL of the paid route. Current x402 SDKs fill it in for you. Hand-rolled 402 responses often leave it out.
7. The 402 body is empty or accepts is malformed
Symptom: x402 v2 puts the challenge in a base64 PAYMENT-REQUIRED header, and some servers send {} as the body. Clients and crawlers that read the body find no payment options.
Fix: keep the header, and also return the same decoded JSON as the 402 body. Make sure accepts is a non-empty array of objects, each with scheme, network, asset, amount and payTo.
8. A POST route is described as GET
Symptom: your route takes a JSON body, but the listing (or the validation) treats it as GET, so it sends no body and gets an error instead of a 402.
Fix: declare the body in the discovery metadata. In the Python SDK, pass body_type="json" plus an example input and input_schema to declare_discovery_extension. Make sure the route key says POST too.
9. The route uses a bare wildcard
Symptom: the route is declared as /prices/*, so the listing can't tell agents what goes in the path.
Fix: use a named parameter in the paywall's route pattern, such as GET /prices/:symbol, so the discovery metadata names the path parameter.
10. You changed price or metadata and the listing didn't update
Symptom: the route is listed, but with an old price, description or schema (cdp-sdk #813).
Fix: the Bazaar refreshes a route when it re-crawls it, so a change can take a while to show up. Make a new paid call after the change, then check the crawl time again before assuming it's stuck.
If none of these fit: accepted as "processing", never indexed
Symptom: your challenge is valid, a payment settled through CDP's facilitator, and the facilitator answered with bazaar.status: "processing". CDP's own validation says the route would be accepted. Days later it still isn't in the catalog.
What's known: several sellers have reported this, and as of October 1, 2026 none of the reports has an answer from a maintainer: x402 #3266, x402 #3281, cdp-sdk #830 and cdp-sdk #835. It looks like a problem on CDP's side, and there is no confirmed fix. "Processing" is also returned for routes that do get indexed, so that status alone tells you nothing either way.
What to try: rule out causes 1 to 10 first, since several of them produce the same symptom. Then make one fresh settlement through CDP after your last change. If it's still missing after a few days, add your route and settlement details to one of the open issues above.
Checking it in one call
If you'd rather not decode challenges by hand, Unlisted runs all of these checks against your endpoint and asks CDP for its live index status, including whether CDP would accept the route if it isn't listed yet. It's pay-per-call over x402 (USDC on Base), with no signup, and it only charges if the check completes:
- Check, $0.02: your 402 challenge, the Bazaar declaration, and CDP's live index status.
- Check + real payment, $0.10: all of that, plus one real test payment to your route, which covers cause 1 for you.
POST https://unlisted.sh/diagnose
Content-Type: application/json
{"url": "https://your-api.example.com/paid-route"}
The full guide, kept up to date, is at unlisted.sh/guide. If you've hit a cause that isn't listed here, tell me in the comments and I'll add it.
Unlisted isn't affiliated with Coinbase.
Top comments (0)