Skip to main content

Getting Started

This guide will help you set up and integrate x402-go into your Go applications.

Prerequisites

  • Go 1.21 or later
  • An Ethereum wallet with private key (for facilitator or client)
  • Familiarity with the Gin HTTP framework (for middleware usage)
  • Access to blockchain RPC endpoints (for facilitator)

Installation

Import the packages you need in your Go project:

import (
// Facilitator service and client
"github.com/vorpalengineering/x402-go/facilitator"
"github.com/vorpalengineering/x402-go/facilitator/client"

// Resource server middleware
"github.com/vorpalengineering/x402-go/resource/middleware"

// Resource client (for buyers)
resourceclient "github.com/vorpalengineering/x402-go/resource/client"

// Shared types
"github.com/vorpalengineering/x402-go/types"
)

Running the Facilitator Service

The facilitator service processes payment verification and settlement requests.

1. Set Environment Variables

The facilitator requires a private key for signing and executing on-chain transactions:

export X402_FACILITATOR_PRIVATE_KEY=0x1234567890abcdef...

Security Note: Never commit your private key to version control. Use environment variables or a secure secret manager.

2. Create Configuration

Copy the example configuration:

cp facilitator/config.example.yaml facilitator/config.yaml

Edit facilitator/config.yaml:

server:
host: "0.0.0.0"
port: 4020

# Networks use CAIP-2 identifiers (namespace:reference)
networks:
eip155:8453:
rpc_url: "https://mainnet.base.org"
eip155:84532:
rpc_url: "https://sepolia.base.org"

# Supported scheme-network combinations
supported:
- scheme: "exact"
network: "eip155:8453"
- scheme: "exact"
network: "eip155:84532"

transaction:
timeout_seconds: 120
max_gas_price: "100000000000" # 100 gwei in wei

log:
level: "info" # debug, info, warn, error

3. Start the Service

# Uses facilitator/config.yaml by default
go run ./cmd/facilitator

# Or specify a custom config path
go run ./cmd/facilitator --config=path/to/config.yaml

The facilitator starts on the configured port (default: 4020) and exposes:

EndpointMethodDescription
/supportedGETList supported payment schemes and networks
/verifyPOSTVerify a payment payload
/settlePOSTSettle a payment on-chain

Protecting APIs with Middleware

Add payment requirements to your Gin routes using the resource middleware:

package main

import (
"github.com/gin-gonic/gin"
"github.com/vorpalengineering/x402-go/resource/middleware"
"github.com/vorpalengineering/x402-go/types"
)

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

// Configure x402 middleware
x402 := middleware.NewX402Middleware(&middleware.MiddlewareConfig{
FacilitatorURL: "http://localhost:4020",
DefaultRequirements: types.PaymentRequirements{
Scheme: "exact",
Network: "eip155:8453",
Amount: "1000000", // 1 USDC (6 decimals)
PayTo: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
},
ProtectedPaths: []string{"/api/*"},
RouteResources: map[string]*types.ResourceInfo{
"/api/data": {
Description: "Protected data endpoint",
MimeType: "application/json",
},
},
MaxBufferSize: 5 * 1024 * 1024, // 5 MB max response
DiscoveryEnabled: true,
BaseURL: "https://api.example.com",
DiscoverableEndpoints: []string{"/api/data"},
})

// Apply middleware globally
router.Use(x402.Handler())

// Your routes
router.GET("/api/data", func(c *gin.Context) {
c.JSON(200, gin.H{"data": "protected content"})
})

router.Run(":3000")
}

The middleware implements the full x402 payment flow:

  1. Returns 402 with PAYMENT-REQUIRED header when no payment is provided
  2. Verifies payment with the facilitator
  3. Executes the handler if payment is valid (response is buffered)
  4. Settles payment on-chain after successful response
  5. Returns PAYMENT-RESPONSE header with settlement details

Using the Resource Client

For services that need to pay for resources, use the resource client:

package main

import (
"fmt"
"io"
"log"

"github.com/ethereum/go-ethereum/crypto"
"github.com/vorpalengineering/x402-go/resource/client"
)

func main() {
// Load your private key
privateKey, err := crypto.HexToECDSA("your_private_key_hex")
if err != nil {
log.Fatal(err)
}

// Create resource client
rc := client.NewResourceClient(privateKey)

url := "https://api.example.com/api/data"

// Step 1: Check if resource requires payment
resp, paymentRequired, err := rc.Check("GET", url, "", nil)
if err != nil {
log.Fatal(err)
}

// Step 2: If payment required, inspect requirements and decide to pay
if paymentRequired != nil {
selected := paymentRequired.Accepts[0]

log.Printf("Payment required: %s on %s", selected.Amount, selected.Network)

// Step 3: Pay for resource (generates EIP-3009 authorization)
resp, err = rc.Pay("GET", url, "", nil, &selected)
if err != nil {
log.Fatal(err)
}
}

// Use the response
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Response: %s\n", body)
}

Using the Facilitator Client

For direct integration with a facilitator service:

package main

import (
"fmt"
"log"

"github.com/vorpalengineering/x402-go/facilitator/client"
"github.com/vorpalengineering/x402-go/types"
)

func main() {
c := client.NewClient("http://localhost:4020")

// Get supported schemes
supported, err := c.Supported()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Supported: %+v\n", supported)

// Verify a payment
verifyResp, err := c.Verify(&types.VerifyRequest{
PaymentPayload: paymentPayload,
PaymentRequirements: types.PaymentRequirements{
Scheme: "exact",
Network: "eip155:8453",
Amount: "1000000",
PayTo: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
},
})
if err != nil {
log.Fatal(err)
}

if verifyResp.IsValid {
log.Printf("Payment valid from: %s", verifyResp.Payer)
}

// Settle a payment
settleResp, err := c.Settle(&types.SettleRequest{
PaymentPayload: paymentPayload,
PaymentRequirements: requirements,
})
if err != nil {
log.Fatal(err)
}

if settleResp.Success {
fmt.Printf("Settled: tx=%s, network=%s\n", settleResp.Transaction, settleResp.Network)
}
}

Using the CLI Tool

Build and use the CLI for testing and management:

# Build
go build ./cmd/x402cli

# Check facilitator supported schemes
./x402cli supported -u http://localhost:4020

# Check if a resource requires payment
./x402cli check -u https://api.example.com/api/data

# Browse discovery endpoint
./x402cli browse -u https://api.example.com

# Generate payment requirements
./x402cli req --scheme exact --network eip155:8453 --amount 1000000

# Generate payment payload (requires private key)
./x402cli payload --req requirements.json --private-key 0x...

# Pay for a resource
./x402cli pay -u https://api.example.com/api/data \
-p payload.json --req requirements.json

Docker

Both the facilitator and CLI can be run as containers:

# Start the facilitator service
export X402_FACILITATOR_PRIVATE_KEY=0x...
docker compose up facilitator

# Run a CLI command
docker compose run --rm x402cli supported -u http://facilitator:4020

# Build images without starting
docker compose build

The facilitator mounts facilitator/config.yaml into the container. Ensure the file exists before running:

cp facilitator/config.example.yaml facilitator/config.yaml

Next Steps