ByAUJay
How to Use GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources in Your Dapp
Instant description: Learn exactly how to query Coinbase’s x402 Bazaar discovery endpoint, paginate and parse the response, and wire results into a production dapp that pays per request using x402—complete with TypeScript, React, and backend examples, plus emerging best practices and operational guardrails. This guide is written for startup and enterprise decision-makers who want concrete, up-to-date implementation details.
Why this endpoint matters
The x402 protocol turns the dormant HTTP 402 status code into a payment handshake so your app (or AI agent) can buy access to APIs and content programmatically. The discovery endpoint—GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources—lists x402-enabled resources indexed by the facilitator so your dapp can find, filter, and launch paid calls on-demand. That removes manual integrations and lets you add new paid capabilities dynamically. (docs.cdp.coinbase.com)
- Discovery is part of the official x402 v2 “Bazaar” extension. Servers annotate routes with JSON Schema; facilitators ingest that metadata; clients query a standard discovery endpoint. (docs.cdp.coinbase.com)
- CDP-hosted facilitators are production-ready, layered with KYT/OFAC checks, and currently support Base and Solana, with testnets for prototyping. That’s the simplest way to go live at enterprise grade. (docs.cdp.coinbase.com)
What the endpoint returns (and what it doesn’t)
- Path: GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources
- Query params:
- type: string (filter by protocol, e.g., "http")
- limit: number (default varies; CDP facilitator default is 100)
- offset: number (pagination)
- Response shape:
- resources: array of items like:
- url: string (resource URL you call with x402)
- type: string ("http" at time of writing)
- metadata: object containing discovery info such as description and input/output schemas (JSON Schema) so you can render forms or validate payloads
- total, limit, offset: numbers for paging
- resources: array of items like:
Important nuance: The discovery payload tells you how to call an endpoint and what to expect back; exact price/payment details are negotiated at request time via the x402 402-challenge, not guaranteed in discovery. Plan your UI to surface pricing after the first 402 response. (docs.cdp.coinbase.com)
Quick smoke test (no auth required)
The discovery list on the CDP-hosted facilitator is readable without authentication. Start with a simple curl to prove it’s alive:
curl -s "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?type=http&limit=5" | jq .
You should see a resources array plus pagination fields. The official docs show the same call being made directly without auth in code examples. In production, cache and paginate rather than polling on every view. (docs.cdp.coinbase.com)
End-to-end architecture you can ship
Below is a battle-tested way to add x402 discovery to your dapp with minimal glue code.
- Buyer (client) flow:
- Query discovery to get candidate services and their input/output schemas.
- Let user/agent select a service, build params from the discovered schema.
- Call the service with x402-enabled fetch; handle 402, sign, pay, retry automatically on success.
- Seller (provider) flow (for your own endpoints):
- Register the Bazaar extension in your server middleware, declare input/output JSON Schemas, and your endpoints will auto-index when the facilitator handles payments. (docs.cdp.coinbase.com)
TypeScript: strongly-typed discovery client
Create types that match the documented shape and add defensive parsing to future-proof against schema additions.
// types/x402-bazaar.ts export type X402Resource = { url: string; type: "http" | string; // future-proof; docs show "http" today metadata?: { description?: string; input?: unknown; // JSON Schema fragment output?: unknown; // JSON Schema fragment }; }; export type X402DiscoveryResponse = { resources: X402Resource[]; total: number; limit: number; offset: number; }; // lib/discovery.ts const BASE = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources"; export async function listX402Resources(params: { type?: string; limit?: number; offset?: number; } = {}): Promise<X402DiscoveryResponse> { const qp = new URLSearchParams(); if (params.type) qp.set("type", params.type); if (typeof params.limit === "number") qp.set("limit", String(params.limit)); if (typeof params.offset === "number") qp.set("offset", String(params.offset)); const res = await fetch(`${BASE}?${qp.toString()}`, { // no auth currently required for listing headers: { "Accept": "application/json" }, }); if (!res.ok) { throw new Error(`Discovery failed: ${res.status} ${res.statusText}`); } const json = (await res.json()) as X402DiscoveryResponse; // Basic guards if (!Array.isArray(json.resources)) throw new Error("Malformed discovery response"); return json; }
- The official docs define type, limit, and offset as the query params and show the CDP endpoint and default limit. (docs.cdp.coinbase.com)
Pagination and caching pattern
Do not call discovery on every page load. Cache results for minutes, not seconds, and respect pagination for large catalogs.
// lib/discovery-cache.ts const TTL_MS = 5 * 60 * 1000; let cache: | { at: number; key: string; data: X402DiscoveryResponse } | null = null; export async function getCachedDiscovery(opts = { type: "http", limit: 100, offset: 0 }) { const key = JSON.stringify(opts); if (cache && cache.key === key && Date.now() - cache.at < TTL_MS) { return cache.data; } const data = await listX402Resources(opts); cache = { at: Date.now(), key, data }; return data; }
- The CDP-hosted endpoint defaults to 100 results—plan pagination UIs to “Load more” using offset += limit. (docs.cdp.coinbase.com)
React: render discoverable services and pay on click
Use discovery to generate a catalog UI, then wire to x402 payment helpers. Coinbase’s SDKs expose “fetchWithPayment” so the 402 handshake, signing, and retry are handled automatically. (docs.cdp.coinbase.com)
// components/ServiceGallery.tsx import React, { useEffect, useState } from "react"; import { getCachedDiscovery } from "../lib/discovery-cache"; // Option A: CDP SDK (works with Embedded Wallets) import { fetchWithX402 } from "@coinbase/cdp-core"; // see docs for setup // Option B: Vanilla x402 client libs exist as well (see x402 repo) export const ServiceGallery: React.FC = () => { const [items, setItems] = useState([]); const [busy, setBusy] = useState<string | null>(null); useEffect(() => { getCachedDiscovery({ type: "http", limit: 100, offset: 0 }) .then(r => setItems(r.resources as any[])) .catch(console.error); }, []); async function invoke(url: string) { try { setBusy(url); // This wrapped fetch will handle HTTP 402 payment flows under the hood const wrapped = fetchWithX402(); // create per session as needed const resp = await wrapped(url, { method: "GET" }); const data = await resp.json(); console.log("Paid response", data); alert("Success! Open console for data."); } catch (e) { console.error(e); alert("Payment or fetch failed"); } finally { setBusy(null); } } return ( <div className="grid"> {items.map((r: any) => ( <div key={r.url} className="card"> <h3>{r.metadata?.description ?? r.url}</h3> <p>Type: {r.type}</p> {/* if metadata has input schema, you could render a form dynamically */} <button onClick={() => invoke(r.url)} disabled={busy === r.url}> {busy === r.url ? "Paying..." : "Pay & Call"} </button> </div> ))} </div> ); };
- CDP docs provide “fetchWithX402”/“fetchWithPayment” to perform the x402 flow seamlessly for buyers. (docs.cdp.coinbase.com)
Seller-side: make your own endpoints discoverable (v2)
If you’re monetizing your own APIs, you’ll want your routes auto-indexed by the Bazaar. Register the Bazaar extension and declare input/output schemas. That’s all—no custom indexing job. (docs.cdp.coinbase.com)
Node/Express example:
import express from "express"; import { paymentMiddleware } from "@x402/express"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { registerExactEvmScheme } from "@x402/evm/exact/server"; import { bazaarResourceServerExtension, declareDiscoveryExtension, } from "@x402/extensions/bazaar"; const app = express(); const facilitatorClient = new HTTPFacilitatorClient({ url: "https://x402.org/facilitator", }); const server = new x402ResourceServer(facilitatorClient); registerExactEvmScheme(server); server.registerExtension(bazaarResourceServerExtension); // One paid route with discovery metadata app.use( paymentMiddleware( { "GET /weather": { accepts: { scheme: "exact", price: "$0.001", network: "eip155:84532", payTo: "0x..." }, extensions: { ...declareDiscoveryExtension({ output: { example: { temperature: 72, conditions: "sunny" }, schema: { properties: { temperature: { type: "number" }, conditions: { type: "string" }, }, required: ["temperature", "conditions"], }, }, }), }, }, }, server ) ); app.get("/weather", (_, res) => res.json({ temperature: 72, conditions: "sunny" })); app.listen(4021);
- The docs show v2’s extension-based declarations, with JSON Schema validation, replacing the older v1 pattern. Stick to v2 going forward. (docs.cdp.coinbase.com)
Network and token realities you need to plan for
- CDP-hosted facilitator supports Base and Solana today (plus Base Sepolia and Solana Devnet). This model is production-ready and brings KYT/OFAC checks. If you need other networks or private infra, opt for self-hosted. (docs.cdp.coinbase.com)
- x402 itself is network-agnostic; facilitators implement verification and settlement specifics. Design your buyer to pre-check the network it can pay on and prefer services that match. (docs.cdp.coinbase.com)
- 2025 updates expanded Solana support across x402 specs and facilitator routing—make sure you’re on current SDKs and facilitator versions. (docs.cdp.coinbase.com)
Production-grade filtering strategy
Use the discovery metadata to reduce failed 402 handshakes and “wrong-network” retries:
- Filter by type=http for now (future types may emerge; keep the type check flexible).
- Inspect metadata.output to detect JSON vs other return types and route to the right client.
- Maintain a small allowlist of networks/tokens your users can actually pay with (e.g., USDC on Base or Solana), and reorder the catalog to put those first.
- Cache per-query (type+limit+offset) and expose a “refresh” that invalidates the cache on demand.
All of these patterns are consistent with the documented shape and the v2 extension architecture that carries input/output JSON Schemas. (docs.cdp.coinbase.com)
Payments: how calls actually get paid
When you call a discovered endpoint without payment, you’ll receive HTTP 402 with payment instructions. A compliant x402 client will:
- Parse the 402 response (amount, asset, network, payTo).
- Construct and sign a payment transaction.
- Submit/settle via the facilitator.
- Retry the original request once settled.
Using CDP hooks or core SDKs, this sequence is handled for you. That’s the fastest path to production for web and mobile surfaces. (docs.cdp.coinbase.com)
Backend: scheduled ingest + feature flags
For enterprises, we recommend a backend layer that ingests discovery listings on a schedule and exposes them to clients via your own API:
// worker/ingest.ts import { listX402Resources } from "../lib/discovery"; import { upsertMany } from "../db/catalog"; async function run() { let offset = 0; const limit = 100; while (true) { const page = await listX402Resources({ type: "http", limit, offset }); await upsertMany(page.resources); // normalize & index by url offset += page.resources.length; if (page.resources.length < limit) break; } }
- Feature-flag new resources to subsets of users while you monitor conversion and error rates.
- Attach compliance notes per resource (e.g., internal allow/deny rules by network, token).
Observability and controls
- Log both the discovery resource URL and the eventual paid invocation URL.
- Capture 402 challenge fields (amount, network) and the resulting transaction hash for reconciliation.
- Alert on “402 received but no settlement” or “payment settled but service never returned 2xx.”
- For CDP-hosted routes, you can rely on built-in KYT/OFAC screening and fee-free USDC settlement in production regions; still, track your own business logic outcomes. (docs.cdp.coinbase.com)
Security and compliance posture
- Avoid exposing server secrets in any discovery calls (they aren’t needed).
- If you interact with other CDP REST endpoints, follow the JWT-based auth patterns and keep Secret API Keys server-only. Discovery itself doesn’t require auth, but don’t generalize that to other CDP APIs. (docs.cdp.coinbase.com)
- Only present networks/tokens that your compliance program allows. CDP-hosted gives you a head start but you remain responsible for your app’s policies. (docs.cdp.coinbase.com)
Edge cases and hardening
- Empty results: handle zero-length pages gracefully; show “no services found” with a retry.
- Schema drift: because metadata is JSON Schema, enforce loose parsing and prefer feature detection over strict schema equality; update rendering when you detect new fields. (docs.cdp.coinbase.com)
- Timeouts: treat discovery like a catalog fetch; if it times out, show cached results with a banner.
- Client wallets: Embedded Wallets + x402 is the smoothest buyer UX for web and mobile; verify sign-in and account readiness before payment to avoid 402 loops. (docs.cdp.coinbase.com)
Practical checklist (copy/paste)
- Discovery
- Query GET /platform/v2/x402/discovery/resources with type=http, limit=100.
- Paginate via offset; cache pages for 5–15 minutes.
- Render cards using metadata.description; attach JSON-Schema-driven forms when available. (docs.cdp.coinbase.com)
- Invocation
- Use a payment-enabled fetch (CDP SDK) so 402 → pay → retry is automatic. (docs.cdp.coinbase.com)
- Prefer resources matching your supported networks/tokens. (docs.cdp.coinbase.com)
- Ops
- Log 402 challenge + settlement tx; alert on incomplete flows.
- Run a nightly ingest to pre-index and feature-flag new resources.
- Governance
- Keep Secret API Keys server-side for other CDP REST calls; discovery remains unauthenticated. (docs.cdp.coinbase.com)
- Revisit network support as Coinbase expands (e.g., Solana support changes landed in late 2025). (docs.cdp.coinbase.com)
Advanced: programmatic discovery with the x402 client extensions
You can also query discovery through the x402 client extension APIs rather than raw HTTP. The docs show a “withBazaar” wrapper around a facilitator client that provides helper methods like extensions.discovery.listResources. This is handy when you’re already using x402 SDKs and want typed helpers and the same config for facilitator URLs. (docs.cdp.coinbase.com)
import { HTTPFacilitatorClient } from "@x402/core/http"; import { withBazaar } from "@x402/extensions/bazaar"; const facilitator = withBazaar( new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" }) ); const result = await facilitator.extensions.discovery.listResources({ type: "http", limit: 50, offset: 0, }); console.log(result.resources.length, "services discovered");
Putting it all together: a minimal buyer journey
- Catalog view loads: your backend serves a cached slice of discovery.
- User selects “Weather API” tile. Your client renders a small form based on input schema (city, units).
- User clicks “Pay & Call.” Your x402-aware fetch does:
- GET → server responds 402 with payment details.
- Client signs and pays (e.g., USDC on Base) with the embedded wallet.
- SDK retries and returns 200 + JSON body; your UI shows the result. (docs.cdp.coinbase.com)
Common pitfalls we see (and how to avoid them)
- Assuming discovery lists prices: it doesn’t guarantee pricing. Treat discovery as capability/schema discovery; price comes with the 402 challenge. (docs.cdp.coinbase.com)
- Ignoring networks: an endpoint might only settle on Solana or Base. Filter or reorder to match what your wallet can pay. (docs.cdp.coinbase.com)
- Shipping with v1 assumptions: v2 added formal extensions and JSON Schema; confirm your server libs and examples reference v2. (docs.cdp.coinbase.com)
Where to go next
- Learn the x402 payment handshake and 402 semantics to design better UX and error handling. (docs.cdp.coinbase.com)
- If you’re building your own endpoints, wire the Bazaar extension so your services are discoverable on day one. (docs.cdp.coinbase.com)
- Track network support and facilitator updates as Coinbase continues to expand capabilities and regions. (docs.cdp.coinbase.com)
- Explore the open-source x402 repo for server/client patterns (Express, Go, and more). (github.com)
TL;DR for decision-makers
- Using GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources, your dapp can programmatically discover x402-enabled APIs, render forms from JSON Schema, and pay per call with embedded wallets—no custom onboarding or API-key management. (docs.cdp.coinbase.com)
- CDP-hosted facilitators give you production readiness (KYT/OFAC), with Base and Solana support today and ongoing expansion; your team ships faster with fewer moving parts. (docs.cdp.coinbase.com)
7Block Labs can help you ship this architecture end-to-end—from discovery-driven UX to wallet flows, observability, and compliance reviews—so you can monetize or consume paid APIs with near-zero friction.
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

