Skip to content

Latest commit

 

History

History
840 lines (707 loc) · 26.6 KB

File metadata and controls

840 lines (707 loc) · 26.6 KB
title Quickstart for Sellers
description 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 or SVM compatible wallet)
  • Node.js and npm, Go, or Python and pip installed
  • An existing API or server

Note
There are pre-configured examples available in the x402 repo for both Node.js and Go. There is also 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
npm install @x402/express @x402/core @x402/evm @x402/svm
```
Install the [x402 Next.js middleware package](https://www.npmjs.com/package/@x402/next).
```bash
npm install @x402/next @x402/core @x402/evm @x402/svm
```
Install the [x402 Hono middleware package](https://www.npmjs.com/package/@x402/hono).
```bash
npm install @x402/hono @x402/core @x402/evm @x402/svm
```
Install the [x402 Fastify middleware package](https://www.npmjs.com/package/@x402/fastify).
```bash
npm install @x402/fastify @x402/core @x402/evm @x402/svm
```
Add the x402 Go module to your project:
```bash
go get github.com/coinbase/x402/go
```
[Install the x402 Python package](https://pypi.org/project/x402/) with FastAPI support:
```bash
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
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
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const app = express();

// Your receiving wallet addresses
const evmAddress = "0xYourEvmAddress";
const svmAddress = "YourSolanaAddress";

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

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.001",
            network: "eip155:84532", // Base Sepolia
            payTo: evmAddress,
          },
          {
            scheme: "exact",
            price: "$0.001",
            network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet
            payTo: svmAddress,
          },
        ],
        description: "Weather data",
        mimeType: "application/json",
      },
    },
    new x402ResourceServer(facilitatorClient)
      .register("eip155:84532", new ExactEvmScheme())
      .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()),
  ),
);

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).
Next.js offers two approaches: `paymentProxy` for protecting page routes (or multiple routes at once), and `withX402` for wrapping individual API route handlers. The key difference is that `withX402` only settles payment after a successful response (status \< 400), making it the recommended approach for API routes.

**Option A: `paymentProxy`** — best for page routes or protecting multiple routes with a single config:

```typescript
// proxy.ts
import { paymentProxy } from "@x402/next";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";

export const evmAddress = "0xYourEvmAddress";
export const svmAddress = "YourSolanaAddress";

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

export const server = new x402ResourceServer(facilitatorClient);
server.register("eip155:*", new ExactEvmScheme());
server.register("solana:*", new ExactSvmScheme());

export const proxy = paymentProxy(
  {
    "/protected": {
      accepts: [
        {
          scheme: "exact",
          price: "$0.001",
          network: "eip155:84532", // Base Sepolia
          payTo: evmAddress,
        },
        {
          scheme: "exact",
          price: "$0.001",
          network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet
          payTo: svmAddress,
        },
      ],
      description: "Premium content",
      mimeType: "text/html",
    },
  },
  server,
);

export const config = {
  matcher: ["/protected/:path*"],
};
```

**Option B: `withX402`** — recommended for API routes, settles payment only after a successful response:

```typescript
// app/api/weather/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withX402 } from "@x402/next";
import { server, evmAddress, svmAddress } from "../../../proxy";

const handler = async (_: NextRequest) => {
  return NextResponse.json(
    {
      report: {
        weather: "sunny",
        temperature: 72,
      },
    },
    { status: 200 },
  );
};

export const GET = withX402(
  handler,
  {
    accepts: [
      {
        scheme: "exact",
        price: "$0.001",
        network: "eip155:84532", // Base Sepolia
        payTo: evmAddress,
      },
      {
        scheme: "exact",
        price: "$0.001",
        network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet
        payTo: svmAddress,
      },
    ],
    description: "Access to weather API",
    mimeType: "application/json",
  },
  server,
);
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/hono).
```typescript
import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { paymentMiddleware, x402ResourceServer } from "@x402/hono";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const app = new Hono();
const evmAddress = "0xYourEvmAddress";
const svmAddress = "YourSolanaAddress";

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

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.001",
            network: "eip155:84532", // Base Sepolia
            payTo: evmAddress,
          },
          {
            scheme: "exact",
            price: "$0.001",
            network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet
            payTo: svmAddress,
          },
        ],
        description: "Weather data",
        mimeType: "application/json",
      },
    },
    new x402ResourceServer(facilitatorClient)
      .register("eip155:84532", new ExactEvmScheme())
      .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()),
  ),
);

app.get("/weather", (c) => {
  return c.json({
    report: {
      weather: "sunny",
      temperature: 70,
    },
  });
});

serve({ fetch: app.fetch, port: 4021 });
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/fastify).
```typescript
import Fastify from "fastify";
import { paymentMiddleware, x402ResourceServer } from "@x402/fastify";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const app = Fastify();
const evmAddress = "0xYourEvmAddress";
const svmAddress = "YourSolanaAddress";

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

paymentMiddleware(
  app,
  {
    "GET /weather": {
      accepts: [
        {
          scheme: "exact",
          price: "$0.001",
          network: "eip155:84532", // Base Sepolia
          payTo: evmAddress,
        },
        {
          scheme: "exact",
          price: "$0.001",
          network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet
          payTo: svmAddress,
        },
      ],
      description: "Weather data",
      mimeType: "application/json",
    },
  },
  new x402ResourceServer(facilitatorClient)
    .register("eip155:84532", new ExactEvmScheme())
    .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()),
);

app.get("/weather", async () => {
  return {
    report: {
      weather: "sunny",
      temperature: 70,
    },
  };
});

app.listen({ port: 4021 });
```
Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/go/servers/gin).
```go
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"
    svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server"
    "github.com/gin-gonic/gin"
)

func main() {
    evmAddress := "0xYourEvmAddress"
    svmAddress := "YourSolanaAddress"
    evmNetwork := x402.Network("eip155:84532")                              // Base Sepolia
    svmNetwork := x402.Network("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1")  // Solana Devnet

    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",
                        Price:   "$0.001",
                        Network: "eip155:84532",
                        PayTo:   evmAddress,
                    },
                    {
                        Scheme:  "exact",
                        Price:   "$0.001",
                        Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
                        PayTo:   svmAddress,
                    },
                },
                Description: "Get weather data for a city",
                MimeType:    "application/json",
            },
        },
        Facilitator: facilitatorClient,
        Schemes: []ginmw.SchemeConfig{
            {Network: evmNetwork, Server: evm.NewExactEvmScheme()},
            {Network: svmNetwork, Server: svm.NewExactSvmScheme()},
        },
        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
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.mechanisms.svm.exact import ExactSvmServerScheme
from x402.schemas import Network
from x402.server import x402ResourceServer

app = FastAPI()

# Your receiving wallet addresses
evm_address = "0xYourEvmAddress"
svm_address = "YourSolanaAddress"
EVM_NETWORK: Network = "eip155:84532"  # Base Sepolia
SVM_NETWORK: Network = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"  # Solana Devnet

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

# Create resource server and register schemes
server = x402ResourceServer(facilitator)
server.register(EVM_NETWORK, ExactEvmServerScheme())
server.register(SVM_NETWORK, ExactSvmServerScheme())

# Define protected routes
routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to=evm_address,
                price="$0.001",
                network=EVM_NETWORK,
            ),
            PaymentOption(
                scheme="exact",
                pay_to=svm_address,
                price="$0.001",
                network=SVM_NETWORK,
            ),
        ],
        mime_type="application/json",
        description="Weather report",
    ),
}

# 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
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.mechanisms.svm.exact import ExactSvmServerScheme
from x402.schemas import Network
from x402.server import x402ResourceServerSync

app = Flask(__name__)

# Your receiving wallet addresses
evm_address = "0xYourEvmAddress"
svm_address = "YourSolanaAddress"
EVM_NETWORK: Network = "eip155:84532"  # Base Sepolia
SVM_NETWORK: Network = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"  # Solana Devnet

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

server = x402ResourceServerSync(facilitator)
server.register(EVM_NETWORK, ExactEvmServerScheme())
server.register(SVM_NETWORK, ExactSvmServerScheme())

routes: dict[str, RouteConfig] = {
    "GET /weather": RouteConfig(
        accepts=[
            PaymentOption(
                scheme="exact",
                pay_to=evm_address,
                price="$0.001",
                network=EVM_NETWORK,
            ),
            PaymentOption(
                scheme="exact",
                pay_to=svm_address,
                price="$0.001",
                network=SVM_NETWORK,
            ),
        ],
        mime_type="application/json",
        description="Weather report",
    ),
}

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" or "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1")
    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 a facilitator that supports the Bazaar extension, your endpoints can be listed in the x402 Bazaar, the 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",
      },
      {
        scheme: "exact",
        price: "$0.001",
        network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",  // Solana mainnet
        payTo: "YourSolanaAddress",
      },
    ],
    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 a production facilitator. See the x402 Ecosystem for available options. Example using one facilitator:

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

2. Update Your Network Identifier

Change from testnet to mainnet network identifiers:

```typescript // Testnet → Mainnet network: "eip155:8453", // Base mainnet (was eip155:84532) ``` ```typescript // Testnet → Mainnet network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // Solana mainnet
// For Solana, use a Solana wallet address (base58 format)
payTo: "YourSolanaWalletAddress",
```
```typescript // 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 import { ExactEvmScheme } from "@x402/evm/exact/server"; import { ExactSvmScheme } from "@x402/svm/exact/server";
const server = new x402ResourceServer(facilitatorClient);
server.register("eip155:*", new ExactEvmScheme());
server.register("solana:*", new ExactSvmScheme());
```
```go 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 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

  • Check out the Advanced Example for a more complex payment flow
  • Explore Advanced Concepts like lifecycle hooks for custom logic before/after verification/settlement
  • Explore Extensions like Bazaar for service discovery
  • Get started as a buyer

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.