/discovery/resources to find paid APIs and MCP tools they can use.
Listing is automatic: there is no registration form, account, or manual submission. The facilitator indexes your resource from the payments it processes — if they carry your discovery declaration.
How listing works
Three parties cooperate to get a resource listed:- Your server declares. Your 402 response includes a bazaar discovery declaration describing the endpoint (method, input/output shape, service metadata).
- The buyer’s client echoes. The client copies your declaration from the 402 response into the payment payload it sends to the facilitator. This is required client behavior in x402 v2 — the client must include at least the extension info it received.
- The facilitator catalogs. On
/verifyand/settle, the facilitator extracts the declaration from the payment payload and upserts your catalog entry asynchronously.
Step 2 is where most “my resource never appears” reports come from. If the buyer’s client drops the
extensions object when building its payment payload, the facilitator never sees your declaration — no matter how many payments settle successfully. Use the EXTENSION-RESPONSES header to tell the cases apart./verify as well as /settle. Verification moves no funds, so you can list or refresh a resource without a settled payment.
Declaring your resource
x402 v2 servers declare via thebazaar extension on the 402 response. The @x402/extensions package builds a valid declaration for you (declareDiscoveryExtension), including the JSON schema the facilitator validates against. The declaration lives in the 402 body’s top-level extensions object:
serviceName, tags, and iconUrl fields on the resource object are service-level metadata the Bazaar uses to present your listing; they are persisted along with description and mimeType.
x402 v1 servers declare through outputSchema.input on the payment requirements themselves (with type and method required). Because v1 discovery info rides inside the payment requirements — which your server controls end to end — v1 listing does not depend on the buyer’s client echoing anything.
MCP servers declare per tool. The catalog key is (resource, toolName), so a server exposing several tools at one URL gets one entry per tool.
Reading EXTENSION-RESPONSES
Every/verify and /settle response from the facilitator reports what happened to your declaration via the EXTENSION-RESPONSES header — a base64-encoded JSON object keyed by extension:
A rejected or missing declaration never affects the payment itself: verification and settlement succeed or fail on their own terms.
What gets catalogued
Each entry in/discovery/resources carries:
Refresh semantics
- Entries are upserted on every payment that carries the extension —
accepts, schemas, metadata, andlastUpdatedall refresh. - Refresh is forward-only. Correcting your declaration does not rewrite the catalog until the next extension-carrying payment arrives.
- There is no TTL and no eviction: an entry persists at its last-written state indefinitely.
- There is no re-index endpoint. To force a refresh, make one verify-shaped payment against your own endpoint through a client that echoes extensions —
/verifycatalogs and moves no funds. Confirm with theprocessingheader status.
Endpoints
GET /discovery/resources
Returns
{ items, pagination: { limit, offset, total }, x402Version }, newest first. Responses are cached for about a minute. The legacy /list path redirects here permanently.
GET /discovery/stats
Aggregate catalog and settlement statistics. Note the three catalog counts:catalogEntries but one resource and at most one new host.
Opting out and delisting
- v1: declare
discoverable: falseinsideoutputSchema.inputand the facilitator will not index the resource. - v2: simplest is to omit the
bazaarextension from your 402 — with nothing to echo, nothing is indexed. - Delisting an existing entry is a known gap. Removing or omitting your declaration stops refreshes but does not evict what is already catalogued, and the x402 specification currently defines no delisting semantics at all. Until that is standardized upstream, removal is a manual request — reach out on Discord or open an issue with proof of resource ownership.
Troubleshooting
Need help?
Join our Community
Have questions or want to connect with other developers? Join our Discord server.

