Skip to content

Latest commit

 

History

History
3384 lines (2531 loc) · 112 KB

File metadata and controls

3384 lines (2531 loc) · 112 KB

Bazaar (Discovery Layer)

Source: https://docs.x402.org/core-concepts/bazaar-discovery-layer

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 the 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

The Bazaar currently provides a simple /list endpoint that returns all x402-compatible services registered with the CDP facilitator. Services are automatically opted-in when they use the CDP facilitator and enable the bazaar extension, making discovery frictionless for sellers.

Note: While a discovery layer is live today for the CDP Facilitator, the spec for the marketplace items is open and part of the x402 scheme, meaning any facilitator can create their own discovery layer.

Basic Flow

  1. Discovery: Clients query the /list endpoint to find available services
  2. Selection: Choose a service based on price, capabilities, and requirements
  3. Execution: Use x402 to pay for and access the selected service
  4. No Manual Setup: No API keys, no account creation, just discover and pay

API Reference

List Endpoint

Retrieve all available x402-compatible endpoints:

GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources

Note: The recommended way to use this endpoint is to use the useFacilitator hook as described below.

Response Schema

Each endpoint in the list contains the following fields:

{
  "accepts": [
    {
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "description": "",
      "extra": {
        "name": "USD Coin",
        "version": "2"
      },
      "maxAmountRequired": "200",
      "maxTimeoutSeconds": 60,
      "mimeType": "",
      "network": "eip155:8453",
      "outputSchema": {
        "input": {
          "method": "GET",
          "type": "http"
        },
        "output": null
      },
      "payTo": "0xa2477E16dCB42E2AD80f03FE97D7F1a1646cd1c0",
      "resource": "https://api.example.com/x402/weather",
      "scheme": "exact"
    }
  ],
  "lastUpdated": "2025-08-09T01:07:04.005Z",
  "metadata": {},
  "resource": "https://api.example.com/x402/weather",
  "type": "http",
  "x402Version": 2
}

Quickstart for Buyers

See the full example here for Python and Node.js.

Step 1: Discover Available Services

Fetch the list of available x402 services using the facilitator client:

```typescript theme={null} import { HTTPFacilitatorClient } from "@x402/core/http"; import { withBazaar } from "@x402/extensions";
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});
const client = withBazaar(facilitatorClient);

const response = await client.extensions.discovery.listResources({ type: "http" });

// Filter services under $0.10
const usdcAsset = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
const maxPrice = 100000; // $0.10 in USDC atomic units (6 decimals)

const affordableServices = response.items.filter(item =>
  item.accepts.find(paymentRequirements =>
    paymentRequirements.asset === usdcAsset &&
    Number(paymentRequirements.maxAmountRequired) < maxPrice
  )
);
```
```python theme={null} from x402.http import FacilitatorConfig, HTTPFacilitatorClient
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://api.cdp.coinbase.com/platform/v2/x402")
)

response = await facilitator.list_resources(type="http")

# Filter services under $0.10
usdc_asset = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
max_price = 100000  # $0.10 in USDC atomic units (6 decimals)

affordable_services = [
    item
    for item in response.items
    if any(
        payment_req.asset == usdc_asset
        and int(payment_req.max_amount_required) < max_price
        for payment_req in item.accepts
    )
]
```

Step 2: Call a Discovered Service

Once you've found a suitable service, use an x402 client to call it:

```typescript theme={null} import { wrapAxiosWithPayment, x402Client } from "@x402/axios"; import { registerExactEvmScheme } from "@x402/evm/exact/client"; import axios from "axios"; import { privateKeyToAccount } from "viem/accounts";
// Set up your payment account
const account = privateKeyToAccount("0xYourPrivateKey");
const client = new x402Client();
registerExactEvmScheme(client, { signer: account });

// Select a service from discovery
const selectedService = affordableServices[0];

// Create a payment-enabled client for that service
const api = wrapAxiosWithPayment(
  axios.create({ baseURL: selectedService.resource }),
  client
);

// Select the payment method of your choice
const selectedPaymentRequirements = selectedService.accepts[0];
const inputSchema = selectedPaymentRequirements.outputSchema.input;

// Build the request using the service's schema
const response = await api.request({
  method: inputSchema.method,
  url: inputSchema.resource,
  params: { location: "San Francisco" } // Based on inputSchema
});

console.log("Response data:", response.data);
```
```python theme={null} import asyncio
from eth_account import Account

from x402 import x402Client
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client


async def main() -> None:
    account = Account.from_key("0xYourPrivateKey")
    client = x402Client()
    register_exact_evm_client(client, EthAccountSigner(account))

    # Select a service from discovery (from Step 1)
    selected_service = affordable_services[0]

    # Select the payment method of your choice
    selected_payment_requirements = selected_service.accepts[0]
    input_schema = selected_payment_requirements.output_schema.input

    # Make the request using httpx client
    async with x402HttpxClient(client) as http:
        response = await http.request(
            method=input_schema.method,
            url=input_schema.resource,
            params={"location": "San Francisco"}  # Based on input_schema
        )
        await response.aread()
        print(f"Response data: {response.json()}")


asyncio.run(main())
```

Quickstart for Sellers

Automatic Listing with Bazaar Extension

If your API uses the CDP facilitator for x402 payments, it's automatically listed in the bazaar when you enable the bazaar extension with discoverable: true.

Adding Metadata

To enhance your listing with descriptions and schemas, include them when setting up your x402 middleware. You should include descriptions for each parameter to make it clear for agents to call your endpoints:

```typescript theme={null} import { paymentMiddleware } from "@x402/express"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { registerExactEvmScheme } from "@x402/evm/exact/server"; import { bazaarResourceServerExtension } from "@x402/extensions";
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);

const routes = {
  "GET /weather": {
    price: "$0.001",
    network: "eip155:8453",
    resource: "0xYourAddress",
    description: "Get current weather data for any location",
    extensions: {
      bazaar: {
        discoverable: true,
        inputSchema: {
          queryParams: {
            location: {
              type: "string",
              description: "City name or coordinates",
              required: true
            }
          }
        },
        outputSchema: {
          type: "object",
          properties: {
            temperature: { type: "number" },
            conditions: { type: "string" },
            humidity: { type: "number" }
          }
        }
      }
    }
  }
};

app.use(paymentMiddleware(routes, server));
```
```python theme={null} from fastapi import FastAPI
from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption
from x402.http.middleware.fastapi import PaymentMiddlewareASGI
from x402.http.types import RouteConfig
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.server import x402ResourceServer

app = FastAPI()

# Create facilitator client (CDP mainnet)
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://api.cdp.coinbase.com/platform/v2/x402")
)

# Create resource server and register EVM scheme
server = x402ResourceServer(facilitator)
server.register("eip155:8453", ExactEvmServerScheme())

# Define routes with Bazaar discovery metadata
routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to="0xYourAddress",
                price="$0.001",
                network="eip155:8453",
            ),
        ],
        mime_type="application/json",
        description="Get current weather data for any location",
        extensions={
            "bazaar": {
                "discoverable": True,
                "inputSchema": {
                    "queryParams": {
                        "location": {
                            "type": "string",
                            "description": "City name or coordinates",
                            "required": True,
                        }
                    }
                },
                "outputSchema": {
                    "type": "object",
                    "properties": {
                        "temperature": {"type": "number"},
                        "conditions": {"type": "string"},
                        "humidity": {"type": "number"},
                    },
                },
            }
        },
    ),
}

app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server)
```
```go theme={null} package main
import (
    x402 "github.com/coinbase/x402/go"
    "github.com/coinbase/x402/go/extensions/bazaar"
    "github.com/coinbase/x402/go/extensions/types"
    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/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
        URL: "https://x402.org/facilitator",
    })

    // Create Bazaar Discovery Extension with input/output schemas
    discoveryExtension, _ := bazaar.DeclareDiscoveryExtension(
        bazaar.MethodGET,
        map[string]interface{}{"location": "San Francisco"},
        types.JSONSchema{
            "properties": map[string]interface{}{
                "location": map[string]interface{}{
                    "type":        "string",
                    "description": "City name or coordinates",
                },
            },
            "required": []string{"location"},
        },
        "",
        &types.OutputConfig{
            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"},
                },
            },
        },
    )

    routes := x402http.RoutesConfig{
        "GET /weather": {
            Accepts: x402http.PaymentOptions{{
                Scheme:  "exact",
                PayTo:   "0xYourAddress",
                Price:   "$0.001",
                Network: x402.Network("eip155:8453"),
            }},
            Description: "Get current weather data for any location",
            Extensions: map[string]interface{}{
                types.BAZAAR: discoveryExtension,
            },
        },
    }

    r.Use(ginmw.X402Payment(ginmw.Config{
        Routes:      routes,
        Facilitator: facilitatorClient,
        Schemes: []ginmw.SchemeConfig{{
            Network: x402.Network("eip155:8453"),
            Server:  evm.NewExactEvmScheme(),
        }},
    }))

    r.GET("/weather", func(c *gin.Context) {
        location := c.DefaultQuery("location", "San Francisco")
        c.JSON(200, gin.H{
            "location":    location,
            "temperature": 70,
            "conditions":  "sunny",
            "humidity":    45,
        })
    })

    r.Run(":4021")
}
```

Coming Soon

The x402 Bazaar is rapidly evolving, and your feedback helps us prioritize features.

Support

FAQ

Q: How do I get my service listed? A: If you're using the CDP facilitator, your service is listed once you enable the bazaar extension with discoverable: true.

Q: How can I make endpoint calls more accurate? A: Include descriptions clearly stating what each parameter does and how to call your endpoint, but do so as succinctly as possible.

Q: How does pricing work? A: Listing is free. Services set their own prices per API call, paid via x402.

Q: What networks are supported? A: Currently Base (eip155:8453) and Base Sepolia (eip155:84532) with USDC payments.

Q: Can I list non-x402 services? A: No, only x402-compatible endpoints can be listed. See our Quickstart for Sellers to make your API x402-compatible.

Client / Server

Source: https://docs.x402.org/core-concepts/client-server

This page explains the roles and responsibilities of the client and server in the x402 protocol.

Understanding these roles is essential to designing, building, or integrating services that use x402 for programmatic payments.

Note
Client refers to the technical component making an HTTP request. In practice, this is often the buyer of the resource.

Server refers to the technical component responding to the request. In practice, this is typically the seller of the resource

Client Role

The client is the entity that initiates a request to access a paid resource.

Clients can include:

  • Human-operated applications
  • Autonomous agents
  • Programmatic services acting on behalf of users or systems

Responsibilities

  • Initiate requests: Send an HTTP request to the resource server.
  • Handle payment requirements: Read the 402 Payment Required response and extract payment details.
  • Prepare payment payload: Use the provided payment requirements to construct a valid payment payload.
  • Resubmit request with payment: Retry the request with the PAYMENT-SIGNATURE header containing the signed payment payload.

Clients do not need to manage accounts, credentials, or session tokens beyond their crypto wallet. All interactions are stateless and occur over standard HTTP requests.

Server Role

The server is the resource provider enforcing payment for access to its services.

Servers can include:

  • API services
  • Content providers
  • Any HTTP-accessible resource requiring monetization

Responsibilities

  • Define payment requirements: Respond to unauthenticated requests with an HTTP 402 Payment Required, including all necessary payment details in the response body.
  • Verify payment payloads: Validate incoming payment payloads, either locally or by using a facilitator service.
  • Settle transactions: Upon successful verification, submit the payment for settlement.
  • Provide the resource: Once payment is confirmed, return the requested resource to the client.

Servers do not need to manage client identities or maintain session state. Verification and settlement are handled per request.

Communication Flow

The typical flow between a client and a server in the x402 protocol is as follows:

  1. Client initiates request to the server for a paid resource.
  2. Server responds with 402 Payment Required, including the payment requirements in the response body.
  3. Client prepares and submits a payment payload based on the provided requirements, including it in the PAYMENT-SIGNATURE header (Base64-encoded).
  4. Server verifies the payment payload, either locally or through a facilitator service.
  5. Server settles the payment and confirms transaction completion.
  6. Server responds with the requested resource, including a PAYMENT-RESPONSE header (Base64-encoded) with settlement confirmation, assuming payment was successful.

Summary

In the x402 protocol:

  • The client requests resources and supplies the signed payment payload.
  • The server enforces payment requirements, verifies transactions, and provides the resource upon successful payment.

This interaction is stateless, HTTP-native, and compatible with both human applications and automated agents.

Next, explore:

  • Facilitator — how servers verify and settle payments
  • HTTP 402 — how servers communicate payment requirements to clients

Facilitator

Source: https://docs.x402.org/core-concepts/facilitator

This page explains the role of the facilitator in the x402 protocol.

The facilitator is an optional but recommended service that simplifies the process of verifying and settling payments between clients (buyers) and servers (sellers).

What is a Facilitator?

The facilitator is a service that:

  • Verifies payment payloads submitted by clients.
  • Settles payments on the blockchain on behalf of servers.

By using a facilitator, servers do not need to maintain direct blockchain connectivity or implement payment verification logic themselves. This reduces operational complexity and ensures accurate, real-time validation of transactions.

Facilitator Responsibilities

  • Verify payments: Confirm that the client's payment payload meets the server's declared payment requirements.
  • Settle payments: Submit validated payments to the blockchain and monitor for confirmation.
  • Provide responses: Return verification and settlement results to the server, allowing the server to decide whether to fulfill the client's request.

The facilitator does not hold funds or act as a custodian - it performs verification and execution of onchain transactions based on signed payloads provided by clients.

Why Use a Facilitator?

Using a facilitator provides:

  • Reduced operational complexity: Servers do not need to interact directly with blockchain nodes.
  • Protocol consistency: Standardized verification and settlement flows across services.
  • Faster integration: Services can start accepting payments with minimal blockchain-specific development.

While it is possible to implement verification and settlement locally, using a facilitator accelerates adoption and ensures correct protocol behavior.

Live Facilitators

  1. Currently, CDP hosts a facilitator live on Base mainnet. For more information about getting started, see the CDP Docs.
  • CDP's facilitator offers fee-free settlement on Base and Solana (any EIP-3009 token on Base; any SPL token on Solana, plus Token-2022 for v2)
  1. PayAI hosts a facilitator on Solana, Base, Polygon, and more. More info & docs at https://docs.payai.network/x402.

Interaction Flow

  1. Client makes an HTTP request to a resource server
  2. Resource server responds with a 402 Payment Required status and a Payment Required Response JSON object in the response body.
  3. Client selects one of the paymentDetails returned by the accepts field of the server response and creates a Payment Payload based on the scheme of the paymentDetails they have selected.
  4. Client sends the HTTP request with the PAYMENT-SIGNATURE header containing the Payment Payload (Base64-encoded) to the resource server
  5. Resource server verifies the Payment Payload is valid either via local verification or by POSTing the Payment Payload and Payment Details to the /verify endpoint of the facilitator server.
  6. Facilitator server performs verification of the object based on the scheme and networkId of the Payment Payload and returns a Verification Response
  7. If the Verification Response is valid, the resource server performs the work to fulfill the request. If the Verification Response is invalid, the resource server returns a 402 Payment Required status and a Payment Required Response JSON object in the response body.
  8. Resource server either settles the payment by interacting with a blockchain directly, or by POSTing the Payment Payload and Payment Details to the /settle endpoint of the facilitator server.
  9. Facilitator server submits the payment to the blockchain based on the scheme and networkId of the Payment Payload.
  10. Facilitator server waits for the payment to be confirmed on the blockchain.
  11. Facilitator server returns a Payment Execution Response to the resource server.
  12. Resource server returns a 200 OK response to the Client with the resource they requested as the body of the HTTP response, and a PAYMENT-RESPONSE header containing the Settlement Response as Base64-encoded JSON if the payment was executed successfully.

Summary

The facilitator acts as an independent verification and settlement layer within the x402 protocol. It helps servers confirm payments and submit transactions onchain without requiring direct blockchain infrastructure.

Next, explore:

  • Client / Server — understand the roles and responsibilities of clients and servers
  • HTTP 402 — understand how payment requirements are communicated to clients

HTTP 402

Source: https://docs.x402.org/core-concepts/http-402

For decades, HTTP 402 Payment Required has been reserved for future use. x402 unlocks it, and absolves the internet of its original sin.

What is HTTP 402?

HTTP 402 is a standard, but rarely used, HTTP response status code indicating that payment is required to access a resource.

In x402, this status code is activated to:

  • Inform clients (buyers or agents) that payment is required.
  • Communicate the details of the payment, such as amount, currency, and destination address.
  • Provide the information necessary to complete the payment programmatically.

Why x402 Uses HTTP 402

The primary purpose of HTTP 402 is to enable frictionless, API-native payments for accessing web resources, especially for:

  • Machine-to-machine (M2M) payments (e.g., AI agents).
  • Pay-per-use models such as API calls or paywalled content.
  • Micropayments without account creation or traditional payment rails.

Using the 402 status code keeps x402 protocol natively web-compatible and easy to integrate into any HTTP-based service.

Payment Headers in V2

x402 V2 uses two standardized headers for payment communication:

  • PAYMENT-SIGNATURE: Contains the Base64-encoded payment payload from the client. This header is sent by the client when retrying a request after receiving a 402 response, proving they have authorized payment.
  • PAYMENT-RESPONSE: Contains the Base64-encoded settlement response from the server. This header is returned by the server in the successful response, confirming the payment was verified and settled.

Both headers must contain valid Base64-encoded JSON strings. This encoding ensures compatibility across different HTTP implementations and prevents issues with special characters in JSON payloads.

Summary

HTTP 402 is the foundation of the x402 protocol, enabling services to declare payment requirements directly within HTTP responses. It:

  • Signals payment is required
  • Communicates necessary payment details
  • Integrates seamlessly with standard HTTP workflows

Networks & Token Support

Source: https://docs.x402.org/core-concepts/network-and-token-support

This page explains which blockchain networks and tokens are supported by x402, and how to extend support to additional networks.

V2 Network Identifiers (CAIP-2)

x402 V2 uses CAIP-2 standard network identifiers for unambiguous cross-chain support. This format follows the pattern namespace:reference.

Network Identifier Reference

V1 Name V2 CAIP-2 ID Chain ID Description
base-sepolia eip155:84532 84532 Base Sepolia testnet
base eip155:8453 8453 Base mainnet
solana-devnet solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 - Solana Devnet
solana solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp - Solana Mainnet

Format Explanation

  • EVM networks: eip155:<chainId> where chainId is the numeric chain identifier
  • Solana: solana:<genesisHash> where genesisHash is the first 32 bytes of the genesis block hash

Overview

x402 is designed to work across multiple blockchain networks, with different levels of support depending on the facilitator being used. The protocol itself is network-agnostic, but facilitators need to implement network-specific logic for payment verification and settlement.

Supported Facilitators

Network support in x402 depends on which facilitator you use. Here are the currently available facilitators:

x402.org Facilitator

  • Supports: eip155:84532 (Base Sepolia), solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 (Solana Devnet)
  • Notes: Recommended for testing and development. This is the default facilitator in the x402 packages and requires no setup.

CDP's x402 Facilitator

  • Supports: eip155:8453 (Base), eip155:84532 (Base Sepolia), solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp (Solana), solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 (Solana Devnet)
  • Notes: Production-ready for mainnet payments with KYT/OFAC compliance checks. Can also be used for testing on Base Sepolia. Requires CDP API keys. Uses facilitator object instead of facilitator URL.
  • Requirements: CDP account and API keys from cdp.coinbase.com, see Quickstart for Sellers: Running on Mainnet for more details.

x402.rs Facilitator

  • Supports: eip155:84532 (Base Sepolia), eip155:8453 (Base), XDC Mainnet
  • Notes: Rust-based facilitator operated by the x402 community.
  • URL: https://facilitator.x402.rs

PayAI Facilitator

  • Supports: Solana, Base, Polygon, Avalanche, Sei, Peaq, Iotex and all of their testnets.
  • Notes: Production-ready for mainnet payments. Supports all tokens on Solana, supports EIP-3009 tokens on EVM-Based chains.
  • URL: https://facilitator.payai.network

Self-Hosted Facilitators

  • Supports: Any EVM network
  • Notes: Run your own facilitator for full control and customization. Supports networks like Avalanche, Polygon, Arbitrum, and other EVM-compatible chains.
  • Setup: See "Adding Support for New Networks" section below

Third-Party Facilitators

Additional facilitators may be available from external providers. Check the x402 Discord community for the latest facilitator offerings.

Token Support

x402 supports tokens on both EVM and Solana networks:

  • EVM: Any ERC-20 token that implements the EIP-3009 standard
  • Solana: Any SPL or token-2022 token

Important: Facilitators support networks, not specific tokens — any EIP-3009 compatible token works on EVM networks, and any SPL/token-2022 token works on Solana, for the facilitators that support those networks.

EVM: EIP-3009 Requirement

Tokens must implement the transferWithAuthorization function from the EIP-3009 standard. This enables:

  • Gasless transfers: The facilitator sponsors gas fees
  • Signature-based authorization: Users sign transfer authorizations off-chain
  • Secure payments: Transfers are authorized by cryptographic signatures

Specifying Payment Amounts

When configuring payment requirements, you have two options:

  1. Price String (e.g., "$0.01") - The system infers USDC as the token
  2. TokenAmount - Specify exact atomic units of any EIP-3009 token

Using Custom EIP-3009 Tokens

To use a custom EIP-3009 token, you need three key pieces of information:

  1. Token Address: The contract address of your EIP-3009 token
  2. EIP-712 Name: The token's name for EIP-712 signatures
  3. EIP-712 Version: The token's version for EIP-712 signatures

Finding Token Information on Basescan

You can retrieve the required EIP-712 values from any block explorer:

  1. Name: Read the name() function - Example on Basescan
  2. Version: Read the version() function - Example on Basescan

These values are used in the eip712 nested object when configuring TokenAmount:

{
  eip712: {
    name: "USD Coin",    // From name() function
    version: "2"         // From version() function
  }
}

Solana: SPL Tokens & Token 2022 Tokens

On Solana, x402 supports all SPL tokens and Token 2022 tokens. When using facilitators that support Solana or Solana Devnet, payments can be made in any SPL/token-2022 token, including USDC (SPL). No EIP-712 configuration is required on Solana.

USDC - The Default Token

  • Status: Supported by default across all networks
  • Why: USDC implements EIP-3009 and is widely available
  • Networks: Available on eip155:8453 (Base), eip155:84532 (Base Sepolia), and all supported networks

Why EIP-3009?

The EIP-3009 standard is essential for x402 because it enables:

  1. Gas abstraction: Buyers don't need native tokens (ETH, MATIC, etc.) for gas
  2. One-step payments: No separate approval transactions required
  3. Universal facilitator support: Any EIP-3009 token works with any facilitator

Quick Reference

Facilitator Networks Supported (CAIP-2) Production Ready Requirements
x402.org eip155:84532, solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 Testnet only None
CDP Facilitator eip155:8453, eip155:84532, solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp, solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 Yes CDP API keys
x402.rs eip155:84532, eip155:8453, xdc Yes None
PayAI Facilitator solana, solana-devnet, base, base-sepolia, polygon, polygon-amoy, avalanche, avalanche-fuji, sei, sei-testnet, peaq, iotex Yes None
Self-hosted Any EVM network (CAIP-2 format) Yes Technical setup

Note: On EVM networks, facilitators support any EIP-3009 compatible token; on Solana, facilitators support any SPL/Token-2022 token.

Adding Support for New Networks

x402 V2 uses dynamic network registration - you can support any EVM network without modifying source files.

V2: Dynamic Registration (Recommended)

In V2, networks are supported through the registration pattern using CAIP-2 identifiers. No source code changes are required:

```typescript theme={null} import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { registerExactEvmScheme } from "@x402/evm/exact/server";
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://your-facilitator.com"  // Facilitator that supports your network
});

const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);  // Registers wildcard support for all EVM chains

// Now use any CAIP-2 network identifier in your routes:
const routes = {
  "GET /api/data": {
    accepts: [{
      scheme: "exact",
      price: "$0.001",
      network: "eip155:43114",  // Avalanche mainnet
      payTo: "0xYourAddress",
    }],
  },
};
```
```go theme={null} import ( x402http "github.com/coinbase/x402/go/http" evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" )
facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
    URL: "https://your-facilitator.com",
})

// Register EVM scheme - supports any CAIP-2 EVM network
schemes := []ginmw.SchemeConfig{
    {Network: x402.Network("eip155:43114"), Server: evm.NewExactEvmScheme()},  // Avalanche
}
```
```python theme={null} from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption from x402.http.types import RouteConfig from x402.mechanisms.evm.exact import ExactEvmServerScheme from x402.server import x402ResourceServer
# Create facilitator client for your network
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://your-facilitator.com")
)

# Create server and register EVM scheme for your network
server = x402ResourceServer(facilitator)
server.register("eip155:43114", ExactEvmServerScheme())  # Avalanche mainnet

# Now use any CAIP-2 network identifier in your routes:
routes: dict[str, RouteConfig] = {
    "GET /api/data": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                price="$0.001",
                network="eip155:43114",  # Avalanche mainnet
                pay_to="0xYourAddress",
            ),
        ],
    ),
}
```

Key Points:

  • Use CAIP-2 format: eip155:<chainId> for any EVM network
  • The scheme implementation handles the network automatically
  • You only need a facilitator that supports your target network (or run your own)

Running Your Own Facilitator

If you need immediate support or want to test before contributing, you can run your own facilitator.

Video Guide: Adding EVM Chains to x402

Prerequisites

  1. Access to an RPC endpoint for your target network
  2. A wallet with native tokens for gas sponsorship
  3. The x402 facilitator code

Future Network Support

The x402 ecosystem is actively expanding network support. Planned additions include:

  • Additional L2 networks
  • Additional non-EVM chain support
  • Cross-chain payment capabilities

Getting Help

For help with network integration:

Summary

x402's network support is designed to be extensible while maintaining security and reliability. Whether you're using the default Base Sepolia (eip155:84532) setup for testing or running your own facilitator for custom networks, the protocol provides flexibility for various use cases.

Key takeaways:

  • Base (eip155:8453) and Base Sepolia (eip155:84532) have the best out-of-the-box support
  • Any EVM network can be supported with a custom facilitator using CAIP-2 format
  • Any EIP-3009 token (with transferWithAuthorization) works on any facilitator
  • Use price strings for USDC or TokenAmount for custom tokens
  • Network choice affects gas costs and payment economics
  • V2 uses CAIP-2 network identifiers for unambiguous cross-chain support

Next, explore:

Wallet

Source: https://docs.x402.org/core-concepts/wallet

This page explains the role of the wallet in the x402 protocol.

In x402, a wallet is both a payment mechanism and a form of unique identity for buyers and sellers. Wallet addresses are used to send, receive, and verify payments, while also serving as identifiers within the protocol.

Role of the Wallet

For Buyers

Buyers use wallets to:

  • Store USDC/crypto
  • Sign payment payloads
  • Authorize onchain payments programmatically

Wallets enable buyers, including AI agents, to transact without account creation or credential management.

For Sellers

Sellers use wallets to:

  • Receive USDC/crypto payments
  • Define their payment destination within server configurations

A seller's wallet address is included in the payment requirements provided to buyers.

CDP's Wallet API is our recommended option for programmatic payments and secure key management.

Summary

  • Wallets enable programmatic, permissionless payments in x402.
  • Buyers use wallets to pay for services.
  • Sellers use wallets to receive payments.
  • Wallet addresses also act as unique identifiers within the protocol.

FAQ

Source: https://docs.x402.org/faq

General

What is x402 in a single sentence?

x402 is an open‑source protocol that turns the dormant HTTP 402 Payment Required status code into a fully‑featured, on‑chain payment layer for APIs, websites, and autonomous agents.

Is x402 a CDP Product?

No. While Coinbase Developer Platform provides tooling and are the creators of the standard, it is an open protocol (Apache-2.0 license) and you don't need any Coinbase products to use it. We look forward to further clarifying this distinction and making x402 a credibly neutral payment standard.

Why not use traditional payment rails or API keys?

Traditional rails require credit‑card networks, user accounts, and multi‑step UI flows.
x402 removes those dependencies, enabling programmatic, HTTP-native payments (perfect for AI agents) while dropping fees to near‑zero and settling in ~1 second.

Is x402 only for crypto‑native projects?

No. Any web API or content provider—crypto or web2—can integrate x402 if it wants a lower‑cost, friction‑free payment path for small or usage‑based transactions.

Language & Framework Support

What languages and frameworks are supported?

Typescript, Python, and Go are reference implementations, but x402 is an open protocol.

Nothing prevents you from implementing the spec in Rust, Java, or other languages. If you're interested in building support for your favorite language, please open an issue and let us know, we'd be happy to help!

Facilitators

Who runs facilitators today?

Coinbase Developer Platform operates the first production facilitator. The protocol, however, is permissionless—anyone can run a facilitator. Expect:

  • Community‑run facilitators for other networks or assets.
  • Private facilitators for enterprises that need custom KYT / KYC flows.

What stops a malicious facilitator from stealing funds or lying about settlement?

Every x402PaymentPayload is signed by the buyer and settles directly on‑chain.
A facilitator that tampers with the transaction will fail signature checks.

Pricing & Schemes

How should I price my endpoint?

There is no single answer, but common patterns are:

  • Flat per‑call (e.g., $0.001 per request)
  • Tiered (/basic vs /pro endpoints with different prices)
  • Up‑to (work in progress): "pay‑up‑to" where the final cost equals usage (tokens, MB, etc.)

Can I integrate x402 with a usage / plan manager like Metronome?

Yes. x402 handles the payment execution. You can still meter usage, aggregate calls, or issue prepaid credits in Metronome and only charge when limits are exceeded. Example glue code is coming soon.

Assets, Networks & Fees

Which assets and networks are supported today?

Network CAIP-2 ID Asset Fees* Status
Base eip155:8453 Any EIP-3009 token fee-free Mainnet
Base Sepolia eip155:84532 Any EIP-3009 token fee-free Testnet
Solana solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp Any SPL token; Token-2022 (v2 only) fee-free Mainnet
Solana Devnet solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 Any SPL token; Token-2022 (v2 only) fee-free Testnet

* Gas paid on chain; Coinbase's x402 facilitator adds zero facilitator fee.

Support for additional chains and assets is on the roadmap and community‑driven.

Does x402 support fiat off‑ramps or credit‑card deposits?

Not natively. However, facilitators or third‑party gateways can wrap x402 flows with on‑ and off‑ramps.

Security

Do I have to expose my private key to my backend?

No. The recommended pattern is:

  1. Buyers (clients/agents) sign locally in their runtime (browser, serverless, agent VM). You can use CDP Wallet API to create a programmatic wallet.
  2. Sellers never hold the buyer's key; they only verify signatures.

How do refunds work?

The current exact scheme is a push payment—irreversible once executed. Two options:

  1. Business‑logic refunds: Seller sends a new USDC transfer back to the buyer.
  2. Escrow schemes: Future spec could add conditional transfers (e.g., HTLCs or hold invoices).

Usage by AI Agents

How does an agent know what to pay?

Agents follow the same flow as humans:

  1. Make a request.
  2. Parse the PAYMENT-REQUIRED header.
  3. Choose a suitable requirement and sign a payload via the x402 client SDKs.
  4. Retry with the PAYMENT-SIGNATURE header.

Do agents need wallets?

Yes. Programmatic wallets (e.g., CDP Wallet API, viem, ethers‑v6 HD wallets) let agents sign EIP‑712 payloads without exposing seed phrases.

Governance & Roadmap

Is there a formal spec or whitepaper?

How will x402 evolve?

Tracked in public GitHub issues + community RFCs. Major themes:

  • Multi‑asset support
  • Additional schemes (upto, stream, permit2)
  • Discovery layer for service search & reputation

Why is x402 hosted in the Coinbase GitHub?

We acknowledge that the repo is primarily under Coinbase ownership today. This is primarily to leverage our best-in-house security and auditing team to ensure the spec is safe and nobody accidentally creates legally ambiguous payment flows. We intend to eventually transfer ownership of the repo to a steering group or open-source committee.

Troubleshooting

I keep getting 402 Payment Required, even after attaching PAYMENT-SIGNATURE. Why?

  1. Signature is invalid (wrong chain ID or payload fields).
  2. Payment amount is less than the required amount in the payment requirements.
  3. Address has insufficient USDC or was flagged by KYT.
    Check the error field in the server's JSON response for details.

My test works on Base Sepolia but fails on Base mainnet—what changed?

  • Ensure you set network: "eip155:8453" (Base mainnet) instead of "eip155:84532" (Base Sepolia).
  • Confirm your wallet has mainnet USDC.
  • Gas fees are higher on mainnet; fund the wallet with a small amount of ETH for gas.

Still have questions?

• Reach out in the Discord channel
• Open a GitHub Discussion or Issue in the x402 repo

Quickstart for Buyers

Source: https://docs.x402.org/getting-started/quickstart-for-buyers

This guide walks you through how to use x402 to interact with services that require payment. By the end of this guide, you will be able to programmatically discover payment requirements, complete a payment, and access a paid resource.

Prerequisites

Before you begin, ensure you have:

  • A crypto wallet with USDC (any EVM-compatible wallet)
  • Node.js and npm, Go, or Python and pip
  • A service that requires payment via x402

Note
We have pre-configured examples available in our repo, including examples for fetch, Axios, Go, and MCP.

1. Install Dependencies

Install the x402 client packages:
```bash theme={null}
# For fetch-based clients
npm install @x402/fetch @x402/evm

# For axios-based clients
npm install @x402/axios @x402/evm

# For Solana support, also add:
npm install @x402/svm
```
Add the x402 Go module to your project:
```bash theme={null}
go get github.com/coinbase/x402/go
```
Install the [x402 package](https://pypi.org/project/x402/) with your preferred HTTP client:
```bash theme={null}
# For httpx (async) - recommended
pip install "x402[httpx]"

# For requests (sync)
pip install "x402[requests]"

# For Solana support, also add:
pip install "x402[svm]"
```

2. Create a Wallet Signer

Install the required package:
```bash theme={null}
npm install viem
```

Then instantiate the wallet signer:

```typescript theme={null}
import { privateKeyToAccount } from "viem/accounts";

// Create a signer from private key (use environment variable)
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
```
```go theme={null} import ( evmsigners "github.com/coinbase/x402/go/signers/evm" )
// Load private key from environment
evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY"))
if err != nil {
    log.Fatal(err)
}
```
Install the required package:
```bash theme={null}
pip install eth_account
```

Then instantiate the wallet signer:

```python theme={null}
import os
from eth_account import Account
from x402.mechanisms.evm import EthAccountSigner

account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
signer = EthAccountSigner(account)
```

Solana (SVM)

Use SolanaKit to instantiate a signer:

import { createKeyPairSignerFromBytes } from '@solana/kit';
import { base58 } from '@scure/base';

// 64-byte base58 secret key (private + public)
const svmSigner = await createKeyPairSignerFromBytes(
  base58.decode(process.env.SOLANA_PRIVATE_KEY!)
);

3. Make Paid Requests Automatically

**@x402/fetch** extends the native `fetch` API to handle 402 responses and payment headers for you. [Full example here](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/fetch)
```typescript theme={null}
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

// Create signer
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);

// Create x402 client and register EVM scheme
const client = new x402Client();
registerExactEvmScheme(client, { signer });

// Wrap fetch with payment handling
const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// Make request - payment is handled automatically
const response = await fetchWithPayment("https://api.example.com/paid-endpoint", {
  method: "GET",
});

const data = await response.json();
console.log("Response:", data);

// Get payment receipt from response headers
if (response.ok) {
  const httpClient = new x402HTTPClient(client);
  const paymentResponse = httpClient.getPaymentSettleResponse(
    (name) => response.headers.get(name)
  );
  console.log("Payment settled:", paymentResponse);
}
```
**@x402/axios** adds a payment interceptor to Axios, so your requests are retried with payment headers automatically. [Full example here](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/axios)
```typescript theme={null}
import { x402Client, wrapAxiosWithPayment, x402HTTPClient } from "@x402/axios";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import axios from "axios";

// Create signer
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);

// Create x402 client and register EVM scheme
const client = new x402Client();
registerExactEvmScheme(client, { signer });

// Create an Axios instance with payment handling
const api = wrapAxiosWithPayment(
  axios.create({ baseURL: "https://api.example.com" }),
  client,
);

// Make request - payment is handled automatically
const response = await api.get("/paid-endpoint");
console.log("Response:", response.data);

// Get payment receipt
const httpClient = new x402HTTPClient(client);
const paymentResponse = httpClient.getPaymentSettleResponse(
  (name) => response.headers[name.toLowerCase()]
);
console.log("Payment settled:", paymentResponse);
```
[Full example here](https://github.com/coinbase/x402/tree/main/examples/go/clients/http)
```go theme={null}
package main

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "time"

    x402 "github.com/coinbase/x402/go"
    x402http "github.com/coinbase/x402/go/http"
    evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client"
    evmsigners "github.com/coinbase/x402/go/signers/evm"
)

func main() {
    url := "http://localhost:4021/weather"

    // Create EVM signer
    evmSigner, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY"))

    // Create x402 client and register EVM scheme
    x402Client := x402.Newx402Client().
        Register("eip155:*", evm.NewExactEvmScheme(evmSigner))

    // Wrap HTTP client with payment handling
    httpClient := x402http.WrapHTTPClientWithPayment(
        http.DefaultClient,
        x402http.Newx402HTTPClient(x402Client),
    )

    // Make request - payment is handled automatically
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    resp, err := httpClient.Do(req)
    if err != nil {
        fmt.Printf("Request failed: %v\n", err)
        return
    }
    defer resp.Body.Close()

    // Read response
    var data map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&data)
    fmt.Printf("Response: %+v\n", data)

    // Check payment response header
    paymentHeader := resp.Header.Get("PAYMENT-RESPONSE")
    if paymentHeader != "" {
        fmt.Println("Payment settled successfully!")
    }
}
```
**httpx** provides async HTTP client support with automatic 402 payment handling.
[Full HTTPX example](https://github.com/coinbase/x402/tree/main/examples/python/clients/httpx) | [Full Requests example](https://github.com/coinbase/x402/tree/main/examples/python/clients/requests)

```python theme={null}
import asyncio
import os
from eth_account import Account

from x402 import x402Client
from x402.http import x402HTTPClient
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client


async def main() -> None:
    client = x402Client()
    account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
    register_exact_evm_client(client, EthAccountSigner(account))

    http_client = x402HTTPClient(client)

    async with x402HttpxClient(client) as http:
        response = await http.get("https://api.example.com/paid-endpoint")
        await response.aread()

        print(f"Response: {response.text}")

        if response.is_success:
            settle_response = http_client.get_payment_settle_response(
                lambda name: response.headers.get(name)
            )
            print(f"Payment settled: {settle_response}")


asyncio.run(main())
```
**requests** provides sync HTTP client support with automatic 402 payment handling.
[Full Requests example](https://github.com/coinbase/x402/tree/main/examples/python/clients/requests)

```python theme={null}
import os
from eth_account import Account

from x402 import x402ClientSync
from x402.http import x402HTTPClientSync
from x402.http.clients import x402_requests
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client


def main() -> None:
    client = x402ClientSync()
    account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
    register_exact_evm_client(client, EthAccountSigner(account))

    http_client = x402HTTPClientSync(client)

    with x402_requests(client) as session:
        response = session.get("https://api.example.com/paid-endpoint")

        print(f"Response: {response.text}")

        if response.ok:
            settle_response = http_client.get_payment_settle_response(
                lambda name: response.headers.get(name)
            )
            print(f"Payment settled: {settle_response}")


main()
```

Multi-Network Client Setup

You can register multiple payment schemes to handle different networks:

```typescript theme={null} import { wrapFetchWithPayment } from "@x402/fetch"; import { x402Client } from "@x402/core/client"; import { registerExactEvmScheme } from "@x402/evm/exact/client"; import { registerExactSvmScheme } from "@x402/svm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { base58 } from "@scure/base";
// Create signers
const evmSigner = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const svmSigner = await createKeyPairSignerFromBytes(
  base58.decode(process.env.SOLANA_PRIVATE_KEY!)
);

// Create client with multiple schemes
const client = new x402Client();
registerExactEvmScheme(client, { signer: evmSigner });
registerExactSvmScheme(client, { signer: svmSigner });

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// Now handles both EVM and Solana networks automatically!
```
```go theme={null} import ( x402 "github.com/coinbase/x402/go" x402http "github.com/coinbase/x402/go/http" evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" evmsigners "github.com/coinbase/x402/go/signers/evm" svmsigners "github.com/coinbase/x402/go/signers/svm" )
// Create signers
evmSigner, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY"))
svmSigner, _ := svmsigners.NewClientSignerFromPrivateKey(os.Getenv("SVM_PRIVATE_KEY"))

// Create client with multiple schemes
x402Client := x402.Newx402Client().
    Register("eip155:*", evm.NewExactEvmScheme(evmSigner)).
    Register("solana:*", svm.NewExactSvmScheme(svmSigner))

// Wrap HTTP client with payment handling
httpClient := x402http.WrapHTTPClientWithPayment(
    http.DefaultClient,
    x402http.Newx402HTTPClient(x402Client),
)

// Now handles both EVM and Solana networks automatically!
```
```python theme={null} import asyncio import os
from eth_account import Account

from x402 import x402Client
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client
from x402.mechanisms.svm import KeypairSigner
from x402.mechanisms.svm.exact.register import register_exact_svm_client


async def main() -> None:
    client = x402Client()

    # Register EVM scheme
    account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
    register_exact_evm_client(client, EthAccountSigner(account))

    # Register SVM scheme
    svm_signer = KeypairSigner.from_base58(os.getenv("SVM_PRIVATE_KEY"))
    register_exact_svm_client(client, svm_signer)

    async with x402HttpxClient(client) as http:
        response = await http.get("https://api.example.com/paid-endpoint")
        print(f"Response: {response.text}")


asyncio.run(main())
```

4. Discover Available Services (Optional)

Instead of hardcoding endpoints, you can use the x402 Bazaar to dynamically discover available services. This is especially powerful for building autonomous agents.

// Fetch available services from the Bazaar API
const response = await fetch('https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources');
const services = await response.json();

// Filter services by criteria
const affordableServices = services.items.filter(
  (item) => item.accepts.some((req) => Number(req.amount) < 100000) // Under $0.10
);

console.log('Available services:', affordableServices);

Learn more about service discovery in the Bazaar documentation.

5. Error Handling

Clients will throw errors if:

  • No scheme is registered for the required network
  • The request configuration is missing
  • A payment has already been attempted for the request
  • There is an error creating the payment header

Common error handling:

try {
  const response = await fetchWithPayment(url, { method: 'GET' });
  // Handle success
} catch (error) {
  if (error.message.includes('No scheme registered')) {
    console.error('Network not supported - register the appropriate scheme');
  } else if (error.message.includes('Payment already attempted')) {
    console.error('Payment failed on retry');
  } else {
    console.error('Request failed:', error);
  }
}

Summary

  • Install x402 client packages (@x402/fetch or @x402/axios) and mechanism packages (@x402/evm, @x402/svm)
  • Create a wallet signer
  • Create an x402Client and register payment schemes
  • Use the provided wrapper/interceptor to make paid API requests
  • (Optional) Use the x402 Bazaar to discover services dynamically
  • Payment flows are handled automatically for you

References:

For questions or support, join our Discord.

Quickstart for Sellers

Source: https://docs.x402.org/getting-started/quickstart-for-sellers

This guide walks you through integrating with x402 to enable payments for your API or service. By the end, your API will be able to charge buyers and AI agents for access.

Note: This quickstart begins with testnet configuration for safe testing. When you're ready for production, see Running on Mainnet for the simple changes needed to accept real payments on Base (EVM) and Solana networks.

Prerequisites

Before you begin, ensure you have:

  • A crypto wallet to receive funds (any EVM-compatible wallet)
  • Node.js and npm, Go, or Python and pip installed
  • An existing API or server

Note
We have pre-configured examples available in our repo for both Node.js and Go. We also have an advanced example that shows how to use the x402 SDKs to build a more complex payment flow.

1. Install Dependencies

Install the [x402 Express middleware package](https://www.npmjs.com/package/@x402/express).
```bash theme={null}
npm install @x402/express @x402/core @x402/evm
```
Install the [x402 Next.js middleware package](https://www.npmjs.com/package/@x402/next).
```bash theme={null}
npm install @x402/next @x402/core @x402/evm
```
Install the [x402 Hono middleware package](https://www.npmjs.com/package/@x402/hono).
```bash theme={null}
npm install @x402/hono @x402/core @x402/evm
```
Add the x402 Go module to your project:
```bash theme={null}
go get github.com/coinbase/x402/go
```
[Install the x402 Python package](https://pypi.org/project/x402/) with FastAPI support:
```bash theme={null}
pip install "x402[fastapi]"

# For Solana support, also add:
pip install "x402[svm]"
```
[Install the x402 Python package](https://pypi.org/project/x402/) with Flask support:
```bash theme={null}
pip install "x402[flask]"

# For Solana support, also add:
pip install "x402[svm]"
```

2. Add Payment Middleware

Integrate the payment middleware into your application. You will need to provide:

  • The Facilitator URL or facilitator client. For testing, use https://x402.org/facilitator which works on Base Sepolia and Solana devnet.
  • The routes you want to protect.
  • Your receiving wallet address.
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/express).
```typescript theme={null}
import express from "express";
import { paymentMiddleware } from "@x402/express";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";

const app = express();

// Your receiving wallet address
const payTo = "0xYourAddress";

// Create facilitator client (testnet)
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

// Create resource server and register EVM scheme
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.001", // USDC amount in dollars
            network: "eip155:84532", // Base Sepolia (CAIP-2 format)
            payTo,
          },
        ],
        description: "Get current weather data for any location",
        mimeType: "application/json",
      },
    },
    server,
  ),
);

// Implement your route
app.get("/weather", (req, res) => {
  res.send({
    report: {
      weather: "sunny",
      temperature: 70,
    },
  });
});

app.listen(4021, () => {
  console.log(`Server listening at http://localhost:4021`);
});
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/fullstack/next).
```typescript theme={null}
// middleware.ts
import { paymentProxy } from "@x402/next";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";

const payTo = "0xYourAddress";

const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);

export const middleware = paymentProxy(
  {
    "/api/protected": {
      accepts: [
        {
          scheme: "exact",
          price: "$0.01",
          network: "eip155:84532",
          payTo,
        },
      ],
      description: "Access to protected content",
      mimeType: "application/json",
    },
  },
  server,
);

export const config = {
  matcher: ["/api/protected/:path*"],
};
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/hono).
```typescript theme={null}
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { paymentMiddleware } from "@x402/hono";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";

const app = new Hono();
const payTo = "0xYourAddress";

const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);

app.use(
  paymentMiddleware(
    {
      "/protected-route": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.10",
            network: "eip155:84532",
            payTo,
          },
        ],
        description: "Access to premium content",
        mimeType: "application/json",
      },
    },
    server,
  ),
);

app.get("/protected-route", (c) => {
  return c.json({ message: "This content is behind a paywall" });
});

serve({ fetch: app.fetch, port: 3000 });
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/go/servers/gin).
```go theme={null}
package main

import (
    "net/http"
    "time"

    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/gin-gonic/gin"
)

func main() {
    payTo := "0xYourAddress"
    network := x402.Network("eip155:84532") // Base Sepolia (CAIP-2 format)

    r := gin.Default()

    // Create facilitator client
    facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
        URL: "https://x402.org/facilitator",
    })

    // Apply x402 payment middleware
    r.Use(ginmw.X402Payment(ginmw.Config{
        Routes: x402http.RoutesConfig{
            "GET /weather": {
                Accepts: x402http.PaymentOptions{
                    {
                        Scheme:  "exact",
                        PayTo:   payTo,
                        Price:   "$0.001",
                        Network: network,
                    },
                },
                Description: "Get weather data for a city",
                MimeType:    "application/json",
            },
        },
        Facilitator: facilitatorClient,
        Schemes: []ginmw.SchemeConfig{
            {Network: network, Server: evm.NewExactEvmScheme()},
        },
        SyncFacilitatorOnStart: true,
        Timeout:    30 * time.Second,
    }))

    // Protected endpoint
    r.GET("/weather", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "weather":     "sunny",
            "temperature": 70,
        })
    })

    r.Run(":4021")
}
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/python/servers/fastapi).
```python theme={null}
from typing import Any

from fastapi import FastAPI

from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption
from x402.http.middleware.fastapi import PaymentMiddlewareASGI
from x402.http.types import RouteConfig
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.server import x402ResourceServer

app = FastAPI()

# Your receiving wallet address
pay_to = "0xYourAddress"

# Create facilitator client (testnet)
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://x402.org/facilitator")
)

# Create resource server and register EVM scheme
server = x402ResourceServer(facilitator)
server.register("eip155:84532", ExactEvmServerScheme())

# Define protected routes
routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to=pay_to,
                price="$0.001",  # USDC amount in dollars
                network="eip155:84532",  # Base Sepolia (CAIP-2 format)
            ),
        ],
        mime_type="application/json",
        description="Get current weather data for any location",
    ),
}

# Add payment middleware
app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server)


@app.get("/weather")
async def get_weather() -> dict[str, Any]:
    return {
        "report": {
            "weather": "sunny",
            "temperature": 70,
        }
    }


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=4021)
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/python/servers/flask).
```python theme={null}
from flask import Flask, jsonify

from x402.http import FacilitatorConfig, HTTPFacilitatorClientSync, PaymentOption
from x402.http.middleware.flask import payment_middleware
from x402.http.types import RouteConfig
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.server import x402ResourceServerSync

app = Flask(__name__)

pay_to = "0xYourAddress"

facilitator = HTTPFacilitatorClientSync(
    FacilitatorConfig(url="https://x402.org/facilitator")
)

server = x402ResourceServerSync(facilitator)
server.register("eip155:84532", ExactEvmServerScheme())

routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to=pay_to,
                price="$0.001",
                network="eip155:84532",
            ),
        ],
        mime_type="application/json",
        description="Get current weather data for any location",
    ),
}

payment_middleware(app, routes=routes, server=server)


@app.route("/weather")
def get_weather():
    return jsonify({
        "report": {
            "weather": "sunny",
            "temperature": 70,
        }
    })


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=4021)
```

Route Configuration Interface:

interface RouteConfig {
  accepts: Array<{
    scheme: string; // Payment scheme (e.g., "exact")
    price: string; // Price in dollars (e.g., "$0.01")
    network: string; // Network in CAIP-2 format (e.g., "eip155:84532")
    payTo: string; // Your wallet address
  }>;
  description?: string; // Description of the resource
  mimeType?: string; // MIME type of the response
  extensions?: object; // Optional extensions (e.g., Bazaar)
}

When a request is made to these routes without payment, your server will respond with the HTTP 402 Payment Required code and payment instructions.

3. Test Your Integration

To verify:

  1. Make a request to your endpoint (e.g., curl http://localhost:4021/weather).
  2. The server responds with a 402 Payment Required, including payment instructions in the PAYMENT-REQUIRED header.
  3. Complete the payment using a compatible client, wallet, or automated agent. This typically involves signing a payment payload, which is handled by the client SDK detailed in the Quickstart for Buyers.
  4. Retry the request, this time including the PAYMENT-SIGNATURE header containing the cryptographic proof of payment.
  5. The server verifies the payment via the facilitator and, if valid, returns your actual API response (e.g., { "data": "Your paid API response." }).

4. Enhance Discovery with Metadata (Recommended)

When using the CDP facilitator, your endpoints can be listed in the x402 Bazaar, our discovery layer that helps buyers and AI agents find services. To enable discovery:

{
  "GET /weather": {
    accepts: [
      {
        scheme: "exact",
        price: "$0.001",
        network: "eip155:8453",
        payTo: "0xYourAddress",
      },
    ],
    description: "Get real-time weather data including temperature, conditions, and humidity",
    mimeType: "application/json",
    extensions: {
      bazaar: {
        discoverable: true,
        category: "weather",
        tags: ["forecast", "real-time"],
      },
    },
  },
}

Learn more about the discovery layer in the Bazaar documentation.

5. Error Handling

  • If you run into trouble, check out the examples in the repo for more context and full code.
  • Run npm install or go mod tidy to install dependencies

Running on Mainnet

Once you've tested your integration on testnet, you're ready to accept real payments on mainnet.

1. Update the Facilitator URL

For mainnet, use the CDP facilitator:

```typescript theme={null} const facilitatorClient = new HTTPFacilitatorClient({ url: "https://api.cdp.coinbase.com/platform/v2/x402" }); ``` ```go theme={null} facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://api.cdp.coinbase.com/platform/v2/x402", }) ``` ```python theme={null} from x402.http import FacilitatorConfig, HTTPFacilitatorClient
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://api.cdp.coinbase.com/platform/v2/x402")
)
```
```python theme={null} from x402.http import FacilitatorConfig, HTTPFacilitatorClientSync
facilitator = HTTPFacilitatorClientSync(
    FacilitatorConfig(url="https://api.cdp.coinbase.com/platform/v2/x402")
)
```

2. Update Your Network Identifier

Change from testnet to mainnet network identifiers:

```typescript theme={null} // Testnet → Mainnet network: "eip155:8453", // Base mainnet (was eip155:84532) ``` ```typescript theme={null} // Testnet → Mainnet network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // Solana mainnet
// For Solana, use a Solana wallet address (base58 format)
payTo: "YourSolanaWalletAddress",
```
```typescript theme={null} // Support multiple networks on the same endpoint { "GET /weather": { accepts: [ { scheme: "exact", price: "$0.001", network: "eip155:8453", // Base mainnet payTo: "0xYourEvmAddress", }, { scheme: "exact", price: "$0.001", network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // Solana mainnet payTo: "YourSolanaAddress", }, ], description: "Weather data", }, } ```

3. Register Multiple Schemes (Multi-Network)

For multi-network support, register both EVM and SVM schemes:

```typescript theme={null} import { registerExactEvmScheme } from "@x402/evm/exact/server"; import { registerExactSvmScheme } from "@x402/svm/exact/server";
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
registerExactSvmScheme(server);
```
```go theme={null} import ( evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" )
r.Use(ginmw.X402Payment(ginmw.Config{
    // ...
    Schemes: []ginmw.SchemeConfig{
        {Network: x402.Network("eip155:8453"), Server: evm.NewExactEvmScheme()},
        {Network: x402.Network("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"), Server: svm.NewExactSvmScheme()},
    },
}))
```
```python theme={null} from x402.mechanisms.evm.exact import ExactEvmServerScheme from x402.mechanisms.svm.exact import ExactSvmServerScheme from x402.server import x402ResourceServer
server = x402ResourceServer(facilitator)
server.register("eip155:8453", ExactEvmServerScheme())  # Base mainnet
server.register("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", ExactSvmServerScheme())  # Solana mainnet
```

4. Update Your Wallet

Make sure your receiving wallet address is a real mainnet address where you want to receive USDC payments.

5. Test with Real Payments

Before going live:

  1. Test with small amounts first
  2. Verify payments are arriving in your wallet
  3. Monitor the facilitator for any issues

Warning: Mainnet transactions involve real money. Always test thoroughly on testnet first and start with small amounts on mainnet.


Network Identifiers (CAIP-2)

x402 v2 uses CAIP-2 format for network identifiers:

Network CAIP-2 Identifier
Base Mainnet eip155:8453
Base Sepolia eip155:84532
Solana Mainnet solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
Solana Devnet solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1

See Network Support for the full list.


Next Steps

For questions or support, join our Discord.

Summary

This quickstart covered:

  • Installing the x402 SDK and relevant middleware
  • Adding payment middleware to your API and configuring it
  • Testing your integration
  • Deploying to mainnet with CAIP-2 network identifiers

Your API is now ready to accept crypto payments through x402.

MCP Server with x402

Source: https://docs.x402.org/guides/mcp-server-with-x402

Model Context Protocol (MCP) is a protocol for passing context between LLMs and other AI agents. This page shows how to use the x402 payment protocol with MCP to make paid API requests through an MCP server, and how to connect it to Claude Desktop.

What is this integration?

This guide walks you through running an MCP server that can access paid APIs using the x402 protocol. The MCP server acts as a bridge between Claude Desktop (or any MCP-compatible client) and a paid API (such as the sample weather API in the x402 repo). When Claude (or another agent) calls a tool, the MCP server will:

  1. Detect if the API requires payment (via HTTP 402 with PAYMENT-REQUIRED header)
  2. Automatically handle the payment using your wallet via the registered x402 scheme
  3. Return the paid data to the client (e.g., Claude)

This lets you (or your agent) access paid APIs programmatically, with no manual payment steps.


Prerequisites


Quick Start

1. Install and Build

# Clone the x402 repository
git clone https://github.com/coinbase/x402.git
cd x402/examples/typescript

# Install dependencies and build packages
pnpm install && pnpm build

# Navigate to the MCP client example
cd clients/mcp

2. Configure Claude Desktop

Add the MCP server to your Claude Desktop configuration:

{
  "mcpServers": {
    "demo": {
      "command": "pnpm",
      "args": [
        "--silent",
        "-C",
        "<absolute path to this repo>/examples/typescript/clients/mcp",
        "dev"
      ],
      "env": {
        "EVM_PRIVATE_KEY": "<private key of a wallet with USDC on Base Sepolia>",
        "SVM_PRIVATE_KEY": "<base58-encoded private key of a Solana wallet with USDC on Devnet>",
        "RESOURCE_SERVER_URL": "http://localhost:4021",
        "ENDPOINT_PATH": "/weather"
      }
    }
  }
}

3. Start the x402 Server

Make sure your x402-compatible server is running at the URL specified in RESOURCE_SERVER_URL:

# In another terminal, from the examples/typescript directory
cd servers/express
pnpm dev

4. Restart Claude Desktop

Restart Claude Desktop to load the new MCP server, then ask Claude to use the get-data-from-resource-server tool.


Environment Variables

Variable Description Required
EVM_PRIVATE_KEY Your EVM wallet's private key (0x prefixed) One of EVM or SVM required
SVM_PRIVATE_KEY Your Solana wallet's private key (base58 encoded) One of EVM or SVM required
RESOURCE_SERVER_URL The base URL of the paid API Yes
ENDPOINT_PATH The specific endpoint path (e.g., /weather) Yes

Implementation

The MCP server uses @x402/axios to wrap axios with automatic payment handling:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import axios from 'axios';
import { x402Client, wrapAxiosWithPayment } from '@x402/axios';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { registerExactSvmScheme } from '@x402/svm/exact/client';
import { privateKeyToAccount } from 'viem/accounts';
import { createKeyPairSignerFromBytes } from '@solana/kit';
import { base58 } from '@scure/base';
import { config } from 'dotenv';

config();

const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}`;
const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string;
const baseURL = process.env.RESOURCE_SERVER_URL || 'http://localhost:4021';
const endpointPath = process.env.ENDPOINT_PATH || '/weather';

if (!evmPrivateKey && !svmPrivateKey) {
  throw new Error('At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY must be provided');
}

/**
 * Creates an axios client configured with x402 payment support for EVM and/or SVM.
 */
async function createClient() {
  const client = new x402Client();

  // Register EVM scheme if private key is provided
  if (evmPrivateKey) {
    const evmSigner = privateKeyToAccount(evmPrivateKey);
    registerExactEvmScheme(client, { signer: evmSigner });
  }

  // Register SVM scheme if private key is provided
  if (svmPrivateKey) {
    const svmSigner = await createKeyPairSignerFromBytes(base58.decode(svmPrivateKey));
    registerExactSvmScheme(client, { signer: svmSigner });
  }

  return wrapAxiosWithPayment(axios.create({ baseURL }), client);
}

async function main() {
  const api = await createClient();

  // Create an MCP server
  const server = new McpServer({
    name: 'x402 MCP Client Demo',
    version: '2.0.0',
  });

  // Add a tool that calls the paid API
  server.tool(
    'get-data-from-resource-server',
    'Get data from the resource server (in this example, the weather)',
    {},
    async () => {
      const res = await api.get(endpointPath);
      return {
        content: [{ type: 'text', text: JSON.stringify(res.data) }],
      };
    }
  );

  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

How It Works

The MCP server exposes a tool that, when called, fetches data from a paid API endpoint. If the endpoint requires payment, the x402 axios wrapper automatically handles the payment handshake:

  1. 402 Response: The server returns HTTP 402 with PAYMENT-REQUIRED header
  2. Parse Requirements: The wrapper extracts payment requirements from the header
  3. Create Payment: Uses the registered scheme (EVM or SVM) to create a payment payload
  4. Retry Request: Sends the original request with the PAYMENT-SIGNATURE header
  5. Return Data: Once payment is verified, the data is returned to Claude

Multi-Network Support

The example supports both EVM (Base, Ethereum) and Solana networks. The x402 client automatically selects the appropriate scheme based on the payment requirements:

import { x402Client, wrapAxiosWithPayment } from '@x402/axios';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { registerExactSvmScheme } from '@x402/svm/exact/client';

const client = new x402Client();

// Register EVM scheme for Base/Ethereum payments
registerExactEvmScheme(client, { signer: evmSigner });

// Register SVM scheme for Solana payments
registerExactSvmScheme(client, { signer: svmSigner });

// Now handles both EVM and Solana networks automatically
const httpClient = wrapAxiosWithPayment(axios.create({ baseURL }), client);

When the server returns a 402 response, the client checks the network field in the payment requirements:

  • eip155:* networks use the EVM scheme
  • solana:* networks use the SVM scheme

Response Handling

Payment Required (402)

When a payment is required, the client receives:

HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64-encoded JSON>

The wrapper automatically:

  1. Parses the payment requirements
  2. Creates and signs a payment using the appropriate scheme
  3. Retries the request with the PAYMENT-SIGNATURE header

Successful Response

After payment is processed, the MCP server returns:

{
  "content": [
    {
      "type": "text",
      "text": "{\"report\":{\"weather\":\"sunny\",\"temperature\":70}}"
    }
  ]
}

Architecture Diagram

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Claude Desktop │────▶│   MCP Server    │────▶│  x402 API       │
│                 │     │  (x402 client)  │     │  (paid endpoint)│
└─────────────────┘     └─────────────────┘     └─────────────────┘
        │                       │                       │
        │  1. Call tool         │  2. GET /weather      │
        │                       │                       │
        │                       │  3. 402 + requirements│
        │                       │◀──────────────────────│
        │                       │                       │
        │                       │  4. Sign payment      │
        │                       │                       │
        │                       │  5. Retry with payment│
        │                       │──────────────────────▶│
        │                       │                       │
        │                       │  6. 200 + data        │
        │                       │◀──────────────────────│
        │                       │                       │
        │  7. Return response   │                       │
        │◀──────────────────────│                       │

Dependencies

The example uses these x402 v2 packages:

{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.9.0",
    "@x402/axios": "workspace:*",
    "@x402/evm": "workspace:*",
    "@x402/svm": "workspace:*",
    "axios": "^1.13.2",
    "viem": "^2.39.0",
    "@solana/kit": "^2.1.1",
    "@scure/base": "^1.2.6"
  }
}

How the Pieces Fit Together

  • x402-compatible server: Hosts the paid API (e.g., weather data). Responds with HTTP 402 and PAYMENT-REQUIRED header if payment is required.
  • MCP server (this implementation): Acts as a bridge, handling payment via @x402/axios and exposing tools to MCP clients.
  • Claude Desktop: Calls the MCP tool, receives the paid data, and displays it to the user.

Next Steps

Migration Guide: V1 to V2

Source: https://docs.x402.org/guides/migration-v1-to-v2

This guide helps you migrate from x402 V1 to V2. The V2 protocol introduces standardized identifiers, improved type safety, and a more modular architecture.

Overview

Aspect V1 V2
Payment Header X-PAYMENT PAYMENT-SIGNATURE
Response Header X-PAYMENT-RESPONSE PAYMENT-RESPONSE
Network Format String (base-sepolia) CAIP-2 (eip155:84532)
Version Field x402Version: 1 x402Version: 2
Packages x402, x402-express, x402-axios @x402/core, @x402/express, @x402/axios, @x402/evm

For Buyers

Before (V1)

```typescript theme={null} import { withPaymentInterceptor } from "x402-axios"; import { createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { baseSepolia } from "viem/chains"; import axios from "axios";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
  account,
  chain: baseSepolia,
  transport: http(),
});

// V1 pattern
const api = withPaymentInterceptor(
  axios.create({ baseURL: "https://api.example.com" }),
  walletClient,
);

const response = await api.get("/paid-endpoint");
```
```python theme={null} import os
from eth_account import Account

from x402.clients.httpx import x402HttpxClient

# V1 pattern
account = Account.from_key(os.getenv("PRIVATE_KEY"))

async with x402HttpxClient(account=account, base_url="https://api.example.com") as client:
    response = await client.get("/protected-endpoint")
    print(await response.aread())
```

After (V2)

```typescript theme={null} import { x402Client, wrapAxiosWithPayment } from "@x402/axios"; import { registerExactEvmScheme } from "@x402/evm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import axios from "axios";
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);

// V2 pattern: Create client and register scheme separately
const client = new x402Client();
registerExactEvmScheme(client, { signer });

// Wrap axios with payment handling
const api = wrapAxiosWithPayment(
  axios.create({ baseURL: "https://api.example.com" }),
  client,
);

const response = await api.get("/paid-endpoint");
```
```python theme={null} import asyncio import os
from eth_account import Account

from x402 import x402Client
from x402.http import x402HTTPClient
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client


async def main() -> None:
    # V2 pattern: Create client and register scheme separately
    client = x402Client()
    account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
    register_exact_evm_client(client, EthAccountSigner(account))

    http_client = x402HTTPClient(client)

    async with x402HttpxClient(client) as http:
        response = await http.get("https://api.example.com/paid-endpoint")
        await response.aread()

        print(f"Response: {response.text}")

        if response.is_success:
            settle_response = http_client.get_payment_settle_response(
                lambda name: response.headers.get(name)
            )
            print(f"Payment settled: {settle_response}")


asyncio.run(main())
```

Key Changes

1. **Package rename**: `x402-axios` → `@x402/axios` 2. **Function rename**: `withPaymentInterceptor` → `wrapAxiosWithPayment` 3. **Wallet setup**: Use `x402Client` with `registerExactEvmScheme` helper instead of passing wallet directly 4. **No chain-specific configuration**: The V2 client automatically handles network selection based on payment requirements 1. **Import path changes**: `x402.clients.httpx` → `x402.http.clients` 2. **Signer wrapper**: Wrap `eth_account.Account` with `EthAccountSigner` 3. **Client construction**: Create `x402Client()` first, then register schemes 4. **Environment variable**: `PRIVATE_KEY` → `EVM_PRIVATE_KEY` 5. **Async/Sync variants**: Use `x402Client` for httpx (async), `x402ClientSync` for requests (sync)

For Sellers

Before (V1)

```typescript theme={null} import { paymentMiddleware, FacilitatorConfig } from "x402-express"; import express from "express";
const app = express();

const facilitatorConfig: FacilitatorConfig = {
  url: "https://x402.org/facilitator",
};

app.use(
  paymentMiddleware(facilitatorConfig, {
    "GET /weather": {
      price: "$0.001",
      network: "base-sepolia", // V1 string format
      config: {
        description: "Get weather data",
      },
    },
  }),
);
```
```python theme={null} from typing import Any, Dict
from fastapi import FastAPI

from x402.fastapi.middleware import require_payment

app = FastAPI()

# V1 pattern
app.middleware("http")(
    require_payment(
        path="/weather",
        price="$0.001",
        pay_to_address="0xYourAddress",
        network="base-sepolia",  # V1 string identifier
    )
)

@app.get("/weather")
async def get_weather() -> Dict[str, Any]:
    return {"report": {"weather": "sunny", "temperature": 70}}
```

After (V2)

```typescript theme={null} import express from "express"; import { paymentMiddleware } from "@x402/express"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { registerExactEvmScheme } from "@x402/evm/exact/server";
const app = express();
const payTo = "0xYourAddress";

// V2 pattern: Create facilitator client and resource server
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.001",
            network: "eip155:84532", // V2 CAIP-2 format
            payTo,
          },
        ],
        description: "Get weather data",
        mimeType: "application/json",
      },
    },
    server,
  ),
);
```
```python theme={null} from typing import Any
from fastapi import FastAPI

from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption
from x402.http.middleware.fastapi import PaymentMiddlewareASGI
from x402.http.types import RouteConfig
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.server import x402ResourceServer

app = FastAPI()

# V2 pattern: Create facilitator client and resource server
facilitator = HTTPFacilitatorClient(
    FacilitatorConfig(url="https://x402.org/facilitator")
)

server = x402ResourceServer(facilitator)
server.register("eip155:84532", ExactEvmServerScheme())

# V2: Route config uses accepts array with explicit scheme, network, and pay_to
routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to="0xYourAddress",
                price="$0.001",
                network="eip155:84532",  # V2 CAIP-2 format
            ),
        ],
        mime_type="application/json",
        description="Get weather data",
    ),
}

app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server)


@app.get("/weather")
async def get_weather() -> dict[str, Any]:
    return {"report": {"weather": "sunny", "temperature": 70}}
```

Key Changes

1. **Package rename**: `x402-express` → `@x402/express` 2. **Configuration structure**: Route config now uses `accepts` array with explicit `scheme`, `network`, and `payTo` 3. **Network format**: `base-sepolia` → `eip155:84532` (CAIP-2 standard) 4. **Resource server**: Create `x402ResourceServer` with facilitator client and register schemes using helper functions 5. **Price recipient**: Explicitly specify `payTo` address per route 1. **Import path changes**: `x402.fastapi.middleware` → `x402.http.middleware.fastapi` 2. **Middleware pattern**: `require_payment` decorator → `PaymentMiddlewareASGI` class 3. **Configuration structure**: Route config now uses `RouteConfig` and `PaymentOption` Pydantic models 4. **Network format**: `base-sepolia` → `eip155:84532` (CAIP-2 standard) 5. **Resource server**: Create `x402ResourceServer` and register schemes explicitly 6. **Type hints**: Use modern Python type hints (`dict[str, Any]` instead of `Dict[str, Any]`) 7. **Async/Sync variants**: Use `x402ResourceServer` + `HTTPFacilitatorClient` for FastAPI (async), use `x402ResourceServerSync` + `HTTPFacilitatorClientSync` for Flask (sync)

Network Identifier Mapping

V1 Name V2 CAIP-2 ID Chain ID Description
base-sepolia eip155:84532 84532 Base Sepolia Testnet
base eip155:8453 8453 Base Mainnet
ethereum eip155:1 1 Ethereum Mainnet
sepolia eip155:11155111 11155111 Ethereum Sepolia Testnet
solana-devnet solana:devnet - Solana Devnet
solana solana:mainnet - Solana Mainnet

Package Migration Reference

| V1 Package | V2 Package(s) | | -------------- | ---------------------------- | | `x402` | `@x402/core` | | `x402-express` | `@x402/express` | | `x402-axios` | `@x402/axios` | | `x402-fetch` | `@x402/fetch` | | `x402-hono` | `@x402/hono` | | `x402-next` | `@x402/next` | | (built-in) | `@x402/evm` (EVM support) | | (built-in) | `@x402/svm` (Solana support) | | V1 Import Path | V2 Import Path | | ------------------------- | ----------------------------------------------------- | | `x402.clients.httpx` | `x402.http.clients.x402HttpxClient` | | `x402.clients.requests` | `x402.http.clients.x402_requests` | | `x402.fastapi.middleware` | `x402.http.middleware.fastapi` | | `x402.flask.middleware` | `x402.http.middleware.flask` | | `x402.facilitator` | `x402.http.HTTPFacilitatorClient` | | (new) | `x402.mechanisms.evm.EthAccountSigner` | | (new) | `x402.mechanisms.evm.exact.register_exact_evm_client` | | (new) | `x402.mechanisms.svm.KeypairSigner` | | (new) | `x402.mechanisms.svm.exact.register_exact_svm_client` | | (new) | `x402.server.x402ResourceServer` |
**Installation with extras:**

```bash theme={null}
# V1
pip install x402

# V2 - install with specific extras
pip install "x402[httpx]"      # For async HTTP clients
pip install "x402[requests]"   # For sync HTTP clients
pip install "x402[fastapi]"    # For FastAPI servers
pip install "x402[flask]"      # For Flask servers
pip install "x402[svm]"        # For Solana support
```

Header Changes

If you're implementing custom HTTP handling, update your header names:

```typescript theme={null} // V1 const payment = req.header("X-PAYMENT"); res.setHeader("X-PAYMENT-RESPONSE", responseData);
// V2
const payment = req.header("PAYMENT-SIGNATURE");
res.setHeader("PAYMENT-RESPONSE", responseData);
```
```python theme={null} # V1 payment = request.headers.get("X-PAYMENT") response.headers["X-PAYMENT-RESPONSE"] = response_data
# V2
payment = request.headers.get("PAYMENT-SIGNATURE")
response.headers["PAYMENT-RESPONSE"] = response_data
```

Troubleshooting

### "Cannot find module" errors
Ensure you've installed all V2 packages:

```bash theme={null}
# For buyers
npm install @x402/axios @x402/evm

# For sellers (Express)
npm install @x402/express @x402/core @x402/evm
```
### "ModuleNotFoundError" errors
Ensure you've installed the x402 package with the correct extras:

```bash theme={null}
# For async HTTP clients (httpx)
pip install "x402[httpx]"

# For sync HTTP clients (requests)
pip install "x402[requests]"

# For FastAPI servers
pip install "x402[fastapi]"

# For Flask servers
pip install "x402[flask]"

# For Solana support
pip install "x402[svm]"
```

Payment verification failures

  • Check you're using CAIP-2 network identifiers (eip155:84532 not base-sepolia)
  • Verify your payTo address is correctly configured
  • Ensure the facilitator URL is correct for your network (testnet vs mainnet)

Mixed V1/V2 compatibility

The facilitator supports both V1 and V2 protocols. During migration, your V2 server can still accept payments from V1 clients, but we recommend updating clients to V2 for full feature support.

Next Steps

Welcome to x402

Source: https://docs.x402.org/introduction

This guide will help you understand x402, the open payment standard, and help you get started building or integrating services with x402.

x402 is the open payment standard that enables services to charge for access to their APIs and content directly over HTTP. It is built around the HTTP 402 Payment Required status code and allows clients to programmatically pay for resources without accounts, sessions, or credential management.

With x402, any web service can require payment before serving a response, using crypto-native payments for speed, privacy, and efficiency.

Want to contribute to our docs? The GitBook repo is open to PRs! Our only ask is that you keep these docs as a neutral resource, with no branded content other than linking out to other resources where appropriate.

Note about the docs: These docs are the credibly neutral source of truth for x402, as x402 is a completely open standard under the Apache-2.0 license. Coinbase Developer Platform is currently sponsoring AI-powered docs for users here, as we migrate to our own AI-powered solution on the main x402.org domain.

Why Use x402?

x402 addresses key limitations of existing payment systems:

  • High fees and friction with traditional credit cards and fiat payment processors
  • Incompatibility with machine-to-machine payments, such as AI agents
  • Lack of support for micropayments, making it difficult to monetize usage-based services

Who is x402 for?

  • Sellers: Service providers who want to monetize their APIs or content. x402 enables direct, programmatic payments from clients with minimal setup.
  • Buyers: Human developers and AI agents seeking to access paid services without accounts or manual payment flows.

Both sellers and buyers interact directly through HTTP requests, with payment handled transparently through the protocol.

What Can You Build?

x402 enables a range of use cases, including:

  • API services paid per request
  • AI agents that autonomously pay for API access
  • Paywalls for digital content
  • Microservices and tooling monetized via microtransactions
  • Proxy services that aggregate and resell API capabilities

How Does It Work?

At a high level, the flow is simple:

  1. A buyer requests a resource from a server.
  2. If payment is required, the server responds with 402 Payment Required, including payment instructions.
  3. The buyer prepares and submits a payment payload.
  4. The server verifies and settles the payment using an x402 facilitator's /verify and /settle endpoints.
  5. If payment is valid, the server provides the requested resource.

For more detail, see:

The goal is to make programmatic commerce accessible, permissionless, and developer-friendly.

Get Started

Ready to build? Start here: