The x402 Bazaar is the discovery layer for the x402 ecosystem: a machine-readable catalog that helps developers and AI agents find and integrate with x402-compatible API endpoints. Think of it as a search index for payable APIs, enabling autonomous discovery and consumption of services.
The x402 Bazaar is in early development. While our vision is to build the “Google for agentic endpoints,” we’re currently more like “Yahoo search”: functional but evolving. Features and APIs may change as we gather feedback and expand capabilities.
Overview
The Bazaar solves a critical problem in the x402 ecosystem: discoverability. Without it, x402-compatible endpoints are like hidden stalls in a vast market. The Bazaar provides:
- For Buyers (API Consumers): Programmatically discover available x402-enabled services, understand their capabilities, pricing, and schemas
- For Sellers (API Providers): Automatic visibility for your x402-enabled services to a global audience of developers and AI agents
- For AI Agents: Dynamic service discovery without pre-baked integrations. Query, find, pay, and use
How It Works
In x402 v2, the Bazaar has been codified as an official extension in the reference SDK (@x402/extensions/bazaar). This extension enables:
- Servers declare discovery metadata (input/output schemas) in their route configuration
- Facilitators extract and catalog this metadata when processing payments
- Clients query the facilitator’s
/discovery/resources endpoint to find available services
v1 vs v2
| Aspect | v1 (Deprecated) | v2 (Current) |
|---|
| Discovery data | outputSchema field in PaymentRequirements | extensions.bazaar field in route config |
| Schema validation | None | JSON Schema validation |
| Input specification | Not supported | Full input/output schema support |
Quickstart for Sellers
To make your endpoints discoverable in the Bazaar, you need to:
- Register the Bazaar extension on your resource server
- Declare discovery metadata in your route configuration
Step 1: Install the Extension Package
npm install @x402/extensions
go get github.com/coinbase/x402/go/extensions/bazaar
Node.js (Express)
Go (Gin)
Full example in the Express server 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();
// Create facilitator client
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://x402.org/facilitator",
});
// Create resource server and register extensions
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
server.registerExtension(bazaarResourceServerExtension);
// Configure payment middleware with discovery metadata
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: {
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: "0xYourAddress",
},
extensions: {
// Declare discovery metadata for this endpoint
...declareDiscoveryExtension({
output: {
example: {
temperature: 72,
conditions: "sunny",
humidity: 45,
},
schema: {
properties: {
temperature: { type: "number" },
conditions: { type: "string" },
humidity: { type: "number" },
},
required: ["temperature", "conditions"],
},
},
}),
},
},
},
server,
),
);
app.get("/weather", (req, res) => {
res.json({
temperature: 72,
conditions: "sunny",
humidity: 45,
});
});
app.listen(4021);
package main
import (
"net/http"
x402 "github.com/coinbase/x402/go"
x402http "github.com/coinbase/x402/go/http"
ginmw "github.com/coinbase/x402/go/http/gin"
evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server"
"github.com/coinbase/x402/go/extensions/bazaar"
"github.com/coinbase/x402/go/extensions/types"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Create discovery extension for the endpoint
discoveryExt, _ := bazaar.DeclareDiscoveryExtension(
types.MethodGET,
nil, // No query params required
nil, // No input schema
"", // Not a body method
&types.OutputConfig{
Example: map[string]interface{}{
"temperature": 72,
"conditions": "sunny",
"humidity": 45,
},
Schema: types.JSONSchema{
"properties": map[string]interface{}{
"temperature": map[string]interface{}{"type": "number"},
"conditions": map[string]interface{}{"type": "string"},
"humidity": map[string]interface{}{"type": "number"},
},
"required": []string{"temperature", "conditions"},
},
},
)
r.Use(ginmw.X402Payment(ginmw.Config{
Routes: x402http.RoutesConfig{
"GET /weather": {
Scheme: "exact",
PayTo: "0xYourAddress",
Price: "$0.001",
Network: x402.Network("eip155:84532"),
Extensions: map[string]interface{}{
types.BAZAAR: discoveryExt,
},
},
},
Facilitator: x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
URL: "https://x402.org/facilitator",
}),
Schemes: []ginmw.SchemeConfig{
{Network: x402.Network("eip155:84532"), Server: evm.NewExactEvmScheme()},
},
}))
r.GET("/weather", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"temperature": 72,
"conditions": "sunny",
"humidity": 45,
})
})
r.Run(":4021")
}
Discovery Extension Options
The declareDiscoveryExtension function accepts configuration for different HTTP methods:
// For GET endpoints (query params)
declareDiscoveryExtension({
input: { city: "San Francisco" }, // Example query params
inputSchema: {
properties: {
city: { type: "string", description: "City name" },
},
required: ["city"],
},
output: {
example: { temperature: 72 },
schema: {
properties: {
temperature: { type: "number" },
},
},
},
})
// For POST endpoints (request body)
declareDiscoveryExtension({
input: { prompt: "Hello world" }, // Example body
inputSchema: {
properties: {
prompt: { type: "string", maxLength: 1000 },
},
required: ["prompt"],
},
bodyType: "json", // Signals this is a body method
output: {
example: { response: "Hi there!" },
},
})
Quickstart for Buyers
To discover available services, use the withBazaar wrapper to extend your facilitator client with discovery capabilities.
Step 1: Install Dependencies
npm install @x402/core @x402/extensions @x402/fetch @x402/evm
go get github.com/coinbase/x402/go
Step 2: Query the Discovery Endpoint
import { HTTPFacilitatorClient } from "@x402/core/http";
import { withBazaar } from "@x402/extensions/bazaar";
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
// Create facilitator client with Bazaar extension
const facilitatorClient = withBazaar(
new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" })
);
// Query available services
const discovery = await facilitatorClient.extensions.discovery.listResources({
type: "http", // Filter by protocol type
limit: 20, // Pagination
offset: 0,
});
console.log(`Found ${discovery.resources.length} services`);
// Browse discovered resources
for (const resource of discovery.resources) {
console.log(`- ${resource.url}`);
console.log(` Type: ${resource.type}`);
if (resource.metadata) {
console.log(` Metadata:`, resource.metadata);
}
}
// Select a service and make a paid request
const selectedService = discovery.resources[0];
// Set up x402 client for payments
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
registerExactEvmScheme(client, { signer });
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
// Call the discovered service
const response = await fetchWithPayment(selectedService.url);
const data = await response.json();
console.log("Response:", data);
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
x402 "github.com/coinbase/x402/go"
x402http "github.com/coinbase/x402/go/http"
evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client"
)
func main() {
facilitatorURL := "https://x402.org/facilitator"
// Query discovery endpoint
resp, err := http.Get(facilitatorURL + "/discovery/resources?type=http&limit=20")
if err != nil {
panic(err)
}
defer resp.Body.Close()
var discovery struct {
Resources []struct {
URL string `json:"url"`
Type string `json:"type"`
Metadata map[string]interface{} `json:"metadata"`
} `json:"resources"`
Total int `json:"total"`
}
json.NewDecoder(resp.Body).Decode(&discovery)
fmt.Printf("Found %d services\n", len(discovery.Resources))
// Select a service
if len(discovery.Resources) == 0 {
fmt.Println("No services found")
return
}
selectedURL := discovery.Resources[0].URL
// Create x402 client for payments
client := x402.NewX402Client()
evm.RegisterExactEvmScheme(client, &evm.Config{
PrivateKey: os.Getenv("EVM_PRIVATE_KEY"),
})
// Make paid request
httpClient := x402.WrapHTTPClient(client)
req, _ := http.NewRequest("GET", selectedURL, nil)
paymentResp, err := httpClient.Do(req)
if err != nil {
panic(err)
}
defer paymentResp.Body.Close()
var data map[string]interface{}
json.NewDecoder(paymentResp.Body).Decode(&data)
fmt.Printf("Response: %+v\n", data)
}
API Reference
Discovery Endpoint
Facilitators that support the Bazaar extension expose a discovery endpoint:
GET {facilitator_url}/discovery/resources
Query Parameters
| Parameter | Type | Description |
|---|
type | string | Filter by protocol type (e.g., "http") |
limit | number | Number of resources to return (default: 20) |
offset | number | Offset for pagination (default: 0) |
Response Schema
{
"resources": [
{
"url": "https://api.example.com/weather",
"type": "http",
"metadata": {
"description": "Weather data API",
"input": { ... },
"output": { ... }
}
}
],
"total": 42,
"limit": 20,
"offset": 0
}
CDP Facilitator Discovery Endpoint
The CDP facilitator’s discovery endpoint:
GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources
The default limit is 100 results per request. Use pagination parameters to retrieve additional results.
Extension Architecture
The Bazaar extension follows the x402 v2 extensions pattern:
// Extension structure
{
bazaar: {
info: {
input: {
type: "http",
method: "GET",
queryParams: { ... }
},
output: {
type: "json",
example: { ... }
}
},
schema: {
// JSON Schema validating the info structure
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: { ... }
}
}
}
Key Components
| Component | Purpose |
|---|
bazaarResourceServerExtension | Server extension that enriches declarations with HTTP method info |
declareDiscoveryExtension() | Helper to create properly structured extension declarations |
withBazaar() | Client wrapper that adds discovery query methods |
extractDiscoveryInfo() | Facilitator helper to extract discovery data from payments |
Best Practices
For Sellers
- Provide clear examples: Include realistic
output.example values that demonstrate your API’s response format
- Document inputs: Use
inputSchema with descriptions to help clients understand required parameters
- Use appropriate types: Specify correct JSON Schema types (
string, number, boolean, array, object)
For Buyers
- Cache discovery results: Don’t query discovery on every request
- Handle pagination: Use
offset and limit for large result sets
- Validate compatibility: Check that discovered services support your payment network
Support
FAQ
Q: How do I get my service listed in the Bazaar?
A: Register the bazaarResourceServerExtension on your resource server and include declareDiscoveryExtension() in your route configuration. The facilitator will automatically catalog your service when it processes payments.
Q: Can I opt out of discovery?
A: Yes, simply don’t include the Bazaar extension in your route configuration. Only routes with the extension will be discoverable.
Q: What networks are supported?
A: The Bazaar is network-agnostic. It catalogs services regardless of which payment networks they accept.
Q: How often is the discovery catalog updated?
A: Services are cataloged when the facilitator processes payments. The catalog is refreshed as transactions occur.