Go implementation of the x402 protocol (v2) for verifiable on-chain payments.
- Browse available resources with
x402cli browseorResourceClient.Browse() - Check available payment requirements with
x402cli checkorResourceClient.Check() - Select and fetch payment requirement with
x402cli reqorResourceClient.Requirements() - Create and sign payment payload with
x402cli payloadorResourceClient.Payload() - Pay for resource with
x402cli payorResourceClient.Pay()
- Integrate the
X402Middlewarehandler into your Gin API. - Configure the middleware to protect API routes with payment requirements.
- Generate and verify ownership proofs with
x402cli proof genandx402cli proof verify - Test your configuration with the
x402cliorResourceClient.
OR
- Integrate the
FacilitatorClientdirectly into your Golang API. - Configure the client to handle payment actions.
- Check facilitator supported networks and schemes with
FacilitatorClient.Supported() - Verify payment payload validity with
FacilitatorClient.Verify() - Settle payment payload with
FacilitatorClient.Settle()
- Configure and run the
Facilitatorservice.
x402-go/
├── cmd/
│ ├── facilitator/ # Facilitator service binary
│ └── x402cli/ # CLI tool for checking x402-protected resources
├── facilitator/ # Facilitator server, verification, and settlement logic
│ ├── client/ # Client library for interacting with a facilitator
│ └── config.example.yaml
├── resource/ # Resource server components
│ ├── client/ # Client library for accessing x402-protected resources
│ └── middleware/ # Gin middleware for protecting resources with x402
├── types/ # Shared x402 protocol types
└── utils/ # Shared utilities (EIP-712, CAIP-2 parsing, etc.)
Command-line tool for checking x402-protected resources.
# Build
go build ./cmd/x402cli
# Get supported data from facilitator
./x402cli supported -u http://localhost:4020
Example output:
{
"kinds": [
{
"x402Version": 0,
"scheme": "exact",
"network": "eip155:84532"
}
],
"extensions": [],
"signers": {
"eip155:*": [
"0x123..."
],
"solana:*": []
}
}
Client library for accessing x402-protected resources. Handles EIP-3009 TransferWithAuthorization signing.
import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/vorpalengineering/x402-go/resource/client"
)
// 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)
// Step 1: Check if resource requires payment
resp, paymentRequired, err := rc.Check("GET", "https://api.example.com/data", "", 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 and sends PAYMENT-SIGNATURE header)
resp, err = rc.Pay("GET", "https://api.example.com/data", "", nil, &selected)
if err != nil {
log.Fatal(err)
}
}
// Use the response
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)Gin middleware for protecting API routes with x402 payment verification.
import (
"github.com/vorpalengineering/x402-go/resource/middleware"
"github.com/vorpalengineering/x402-go/types"
)
// Configure middleware
x402 := middleware.NewX402Middleware(&middleware.MiddlewareConfig{
FacilitatorURL: "http://localhost:4020",
DefaultRequirements: types.PaymentRequirements{
Scheme: "exact",
Network: "eip155:8453",
Amount: "1000000",
PayTo: "0x123...",
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
},
ProtectedPaths: []string{"/api/*"},
})
// Apply to your Gin router
router.Use(x402.Handler())The middleware implements the full x402 payment flow:
- Returns
402withPAYMENT-REQUIREDheader when no payment is provided - Verifies payment with the facilitator
- Executes the handler if payment is valid
- Settles payment on-chain after successful response
- Returns
PAYMENT-RESPONSEheader with settlement details
Facilitator service for payment verification and on-chain settlement.
# Set your facilitator's private key
export X402_FACILITATOR_PRIVATE_KEY=0x123abc...
# Copy and edit config
cp facilitator/config.example.yaml facilitator/config.yaml
# Run the facilitator (uses facilitator/config.yaml by default)
go run ./cmd/facilitator
go run ./cmd/facilitator --config=path/to/config.yamlEndpoints:
GET /supported- Returns supported scheme/network combinations, extensions, and signer addressesPOST /verify- Verifies a payment payload against requirementsPOST /settle- Settles a verified payment on-chain via EIP-3009TransferWithAuthorization
Configuration (facilitator/config.yaml):
server:
host: "0.0.0.0"
port: 4020
# Networks use CAIP-2 identifiers
networks:
eip155:8453:
rpc_url: "https://mainnet.base.org"
eip155:84532:
rpc_url: "https://sepolia.base.org"
supported:
- scheme: "exact"
network: "eip155:8453"
transaction:
timeout_seconds: 120
max_gas_price: "100000000000"
log:
level: "info"Client library for communicating with an x402 facilitator.
import (
"github.com/vorpalengineering/x402-go/facilitator/client"
"github.com/vorpalengineering/x402-go/types"
)
fc := client.NewFacilitatorClient("http://localhost:4020")
// Get supported schemes
supported, err := fc.Supported()
// Verify a payment
verifyResp, err := fc.Verify(&types.VerifyRequest{
PaymentPayload: paymentPayload,
PaymentRequirements: types.PaymentRequirements{
Scheme: "exact",
Network: "eip155:8453",
Amount: "1000000",
PayTo: "0x123...",
Asset: "0x833...",
},
})
if verifyResp.IsValid {
// Payment is valid, payer: verifyResp.Payer
}
// Settle a payment
settleResp, err := fc.Settle(&types.SettleRequest{
PaymentPayload: paymentPayload,
PaymentRequirements: requirements,
})
if settleResp.Success {
fmt.Printf("Settled: tx=%s, network=%s\n", settleResp.Transaction, settleResp.Network)
}Both the facilitator and CLI can be run as containers via Docker Compose.
# 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 buildThe facilitator mounts facilitator/config.yaml into the container. Ensure the file exists before running (copy from facilitator/config.example.yaml).
See the facilitator README and CLI README for more details.
This implementation follows x402 protocol version 2. Key aspects:
- CAIP-2 network identifiers (e.g.,
eip155:8453for Base,eip155:1for Ethereum mainnet) - EIP-3009 TransferWithAuthorization for gasless token transfers
- Transport headers:
PAYMENT-SIGNATURE(client request),PAYMENT-REQUIRED(402 response),PAYMENT-RESPONSE(success response) - Payment payload carries the accepted requirements and signed authorization as a base64-encoded JSON object
See the x402 specification for full protocol details.