Go Facilitator
Run a payment facilitator in Go
x402 Facilitator Example
This example demonstrates how to build a simple x402 facilitator that verifies and settles payments on behalf of clients.
What is a Facilitator?
A facilitator is a service that acts as a payment processor in the x402 protocol:
- Verifies payment signatures from clients
- Settles payments by submitting transactions to the blockchain
- Returns confirmation to clients
Facilitators allow clients to create payments without needing to interact with the blockchain directly, making it easier to build payment-enabled applications.
What This Example Shows
- Basic Facilitator Setup: Creating and configuring a facilitator
- Payment Verification: Verifying client payment signatures with idiomatic error handling
- On-chain Settlement: Submitting transactions to the blockchain (EVM + SVM)
- Facilitator Signer Implementation: See
signer.gofor EVM and SVM signer examples - Lifecycle Hooks: Logging verification and settlement operations
- HTTP Endpoints: Exposing /verify, /settle, and /supported APIs
Files in This Example
main.go- Main facilitator server with hooks and endpointssigner.go- Facilitator signer implementations for EVM and SVMREADME.md- This file
Architecture
Client → Resource Server → Facilitator → Blockchain
│ │ │ │
│ │ │ │
│ 1. Request resource │ │
│ 2. Return 402 Payment Required │
│ │ │
│ 3. Create payment │ │
│ 4. Request w/ payment │ │
│ │ │ │
│ │ 5. Verify → │
│ │ ← Valid │ │
│ │ │ │
│ 6. Return resource │ │
│ │ │ │
│ │ 7. Settle → 8. Submit tx →
│ │ ← Success ← ← Confirmed
Signer Implementation
The signer.go file contains reference implementations for EVM and SVM facilitator signers that handle:
- EIP-712 signature verification
- Transaction submission and confirmation
- Balance checking
- RPC client management
For production deployments with additional features (Bazaar discovery, multiple networks), see e2e/facilitators/go/main.go.
Prerequisites
- Go 1.24 or higher
- EVM private key with Base Sepolia ETH for transaction fees
- SVM private key with Solana Devnet SOL for transaction fees (optional)
Setup
- Create a
.envfile:
EVM_PRIVATE_KEY=<your-evm-private-key>
SVM_PRIVATE_KEY=<your-svm-private-key>
⚠️ Security Note: The facilitator private key needs ETH/SOL for gas fees. Use a dedicated testnet account.
- Install dependencies and run:
go mod download
go run .
Error Handling
The facilitator SDK uses idiomatic Go error handling with custom error types:
Success Pattern:
result, err := facilitator.Verify(ctx, payload, requirements)
if err != nil {
return err // Any failure (business logic or system)
}
// result.IsValid is guaranteed to be true
Structured Error Information:
result, err := facilitator.Verify(ctx, payload, requirements)
if err != nil {
// Extract structured error details if needed
if ve, ok := err.(*x402.VerifyError); ok {
log.Printf("Verification failed: reason=%s, payer=%s, network=%s",
ve.Reason, ve.Payer, ve.Network)
}
return err
}
Error Types:
*VerifyError- Verification failures withReason,Payer,Network,Err*SettleError- Settlement failures withReason,Payer,Network,Transaction,Err
This replaces the old pattern of checking both err != nil and response.IsValid == false.
API Endpoints
GET /supported
Returns supported networks and schemes.
Response:
{
"kinds": [
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:84532"
},
{
"x402Version": 2,
"scheme": "exact",
"network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
}
]
}
POST /verify
Verifies a payment signature.
Request:
{
"paymentPayload": {
"x402Version": 2,
"resource": {
"url": "http://localhost:4021/weather",
"description": "Weather data",
"mimeType": "application/json"
},
"accepted": {
"scheme": "exact",
"network": "eip155:84532",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"amount": "1000",
"payTo": "0x...",
"maxTimeoutSeconds": 300,
"extra": { "name": "USDC", "version": "2" }
},
"payload": {
"signature": "0x...",
"authorization": { "from": "0x...", "to": "0x...", "value": "1000", "..." : "..." }
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:84532",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"amount": "1000",
"payTo": "0x...",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
}
}
Response (success):
{
"isValid": true,
"payer": "0x..."
}
Response (failure):
{
"isValid": false,
"invalidReason": "invalid_signature"
}
POST /settle
Settles a verified payment by broadcasting the transaction on-chain.
Request body is identical to /verify.
Response (success):
{
"success": true,
"transaction": "0x...",
"network": "eip155:84532",
"payer": "0x..."
}
Response (failure):
{
"success": false,
"errorReason": "insufficient_balance",
"transaction": "",
"network": "eip155:84532"
}
Extending the Example
Adding Networks
Register additional schemes for other networks:
import (
x402 "github.com/coinbase/x402/go"
evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator"
svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator"
)
facilitator := x402.Newx402Facilitator()
// Register EVM scheme with smart wallet deployment enabled
evmConfig := &evm.ExactEvmSchemeConfig{
DeployERC4337WithEIP6492: true,
}
facilitator.Register([]x402.Network{"eip155:84532"}, evm.NewExactEvmScheme(evmSigner, evmConfig))
// Register SVM scheme
facilitator.Register([]x402.Network{"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"}, svm.NewExactSvmScheme(svmSigner))
Lifecycle Hooks
Add custom logic before/after verify and settle operations:
facilitator := x402.Newx402Facilitator()
facilitator.OnBeforeVerify(func(ctx x402.FacilitatorVerifyContext) (*x402.FacilitatorBeforeHookResult, error) {
// Log or validate before verification
return nil, nil
})
facilitator.OnAfterVerify(func(ctx x402.FacilitatorVerifyResultContext) error {
// Track verified payments
return nil
})
facilitator.OnVerifyFailure(func(ctx x402.FacilitatorVerifyFailureContext) (*x402.FacilitatorVerifyFailureHookResult, error) {
// Handle verification failures
return nil, nil
})
facilitator.OnBeforeSettle(func(ctx x402.FacilitatorSettleContext) (*x402.FacilitatorBeforeHookResult, error) {
// Validate before settlement
// Return &x402.FacilitatorBeforeHookResult{Abort: true, Reason: "..."} to cancel
return nil, nil
})
facilitator.OnAfterSettle(func(ctx x402.FacilitatorSettleResultContext) error {
// Track successful settlements
return nil
})
facilitator.OnSettleFailure(func(ctx x402.FacilitatorSettleFailureContext) (*x402.FacilitatorSettleFailureHookResult, error) {
// Handle settlement failures
return nil, nil
})
Network Identifiers
Networks use CAIP-2 format:
eip155:84532— Base Sepoliaeip155:8453— Base Mainnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1— Solana Devnetsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp— Solana Mainnet
Related Content
Looking for more? Check out our other go examples or browse by facilitator content.