x402 Protocol
x402 is an open HTTP payment protocol that enables machine-to-machine micropayments using blockchain-based stablecoins. It extends the HTTP 402 Payment Required status code into a full request/response payment cycle.
Why x402?
Traditional payment rails require human interactions (card swipes, OAuth redirects) and are unsuitable for AI agents, microservices, or programmatic API monetisation. x402 solves this by:
- Making payments part of the HTTP request - no redirects, no human approval.
- Leveraging smart contract authorization for trustless settlement.
- Supporting ERC-20 / SPL / IBC tokens - not tied to a single chain.
- Enabling micropayments ($0.001 and up) with USDC's stable denomination.
The Payment Flow
1. Client → Resource Server GET /api/data
2. Resource Server → Client 402 Payment Required
X-Payment-Requirements: <JSON>
3. Client signs payment payload (off-chain, locally - no gas)
4. Client → Resource Server GET /api/data
X-Payment: <signed-payload>
5. Resource Server → Facilitator POST /api/v1/verify
6. Resource Server → Facilitator POST /api/v1/settle
7. Facilitator → Blockchain broadcast transaction
8. Facilitator → Resource Server { success: true, txHash: "0x..." }
9. Resource Server → Client 200 OK (content returned)Optional pre-check: The client can call
POST /api/v1/verifydirectly before step 4 to confirm its payload is valid without risking a failed request.
Protocol Objects
The types below are defined in the x402-go library and used directly by the facilitator.
PaymentPayload
The payer constructs and signs this object, then attaches it to the request.
type PaymentPayload struct {
// x402 protocol version. Currently 1.
X402Version int `json:"x402Version"`
// Payment scheme. Currently "exact".
Scheme string `json:"scheme"`
// Target network (e.g. "base-sepolia", "solana-devnet", "osmosis").
Network string `json:"network"`
// Base64-encoded, chain-specific signed transaction or authorization.
Payload string `json:"payload"`
}The Payload field encoding is chain-specific:
| Chain | Encoding |
|---|---|
| EVM (Base) | Base64-encoded EIP-3009 transferWithAuthorization signature |
| Solana | Base64-encoded partially-signed SPL transfer transaction |
| Cosmos | Base64-encoded signed MsgSend transaction bytes |
PaymentRequirements
The resource server advertises this in the 402 response. It fully describes what constitutes a valid payment.
type PaymentRequirements struct {
// Payment scheme (e.g. "exact", "stream").
Scheme string `json:"scheme"`
// Blockchain network (e.g. "base-sepolia", "osmosis").
Network string `json:"network"`
// Maximum amount in the token's atomic unit (e.g. "1000000" = 1 USDC).
// String because Go does not support uint256.
MaxAmountRequired string `json:"maxAmountRequired"`
// URL of the resource being paid for.
Resource string `json:"resource"`
// Human-readable description shown to payers.
Description string `json:"description"`
// Expected MIME type of the resource response.
MimeType string `json:"mimeType"`
// Output schema of the response, if applicable.
OutputSchema map[string]interface{} `json:"outputSchema,omitempty"`
// Recipient wallet address.
PayTo string `json:"payTo"`
// Seconds before the payment authorization expires.
MaxTimeoutSeconds int `json:"maxTimeoutSeconds"`
// Token contract address (ERC-20, SPL mint, or IBC denom).
Asset string `json:"asset"`
// Scheme-specific extra fields (e.g. EIP-712 domain name/version for EVM).
Extra map[string]interface{} `json:"extra,omitempty"`
}JSON example
{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "1000000",
"resource": "/api/premium-data",
"description": "Access to premium data endpoint",
"mimeType": "application/json",
"payTo": "0xMerchantAddress",
"maxTimeoutSeconds": 60,
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"x402Version": 1
}Schemes
exact
The only currently supported scheme. The payer authorises a transfer of exactly maxAmountRequired atomic units of the specified asset to payTo. The facilitator verifies the signature matches these parameters before settling.
Future schemes (e.g. stream, subscription) may be added in later protocol versions.
Chain-Specific Notes
EVM - Base (and other EVM chains)
- Uses EIP-3009
transferWithAuthorization- the payer signs a structured data permit, not a transaction. No gas is required from the payer. - The facilitator holds the settlement wallet and broadcasts the
transferWithAuthorizationcall, paying gas on behalf of the merchant. - The
Extrafield inPaymentRequirementsmay includenameandversionfor EIP-712 domain construction. - USDC contract on Base Sepolia:
0x036CbD53842c5426634e7929541eC2318f3dCF7e
Solana
- The payer creates and partially signs an SPL
transferinstruction. - The base64-encoded serialized transaction is placed in
Payload. - The facilitator co-signs and broadcasts.
- Asset: USDC SPL mint.
Cosmos (Osmosis / CosmosHub / Noble)
- The payer signs a standard
MsgSendtransaction. - The facilitator broadcasts the pre-signed transaction bytes.
- Asset: IBC USDC (e.g. Noble USDC routed via IBC) or native Noble USDC.
- gRPC endpoint required for Cosmos networks.
The x402-go Library
The facilitator is built on top of x402-go - a standalone Go library that handles all chain-specific verification and settlement logic.
import "github.com/vitwit/x402-go"
x := x402.New(cfg,
x402.WithLogger(log),
x402.WithMetrics(recorder),
)
// Add networks
x.AddEVMNetwork("base-sepolia", evmClient)
x.AddSolanaNetwork("solana-devnet", solanaClient)
x.AddCosmosNetwork("osmosis", cosmosClient)
// Verify a payment
result, err := x.Verify(ctx, verifyRequest)
// Settle a payment
result, err := x.Settle(ctx, verifyRequest)The library is chain-agnostic and extensible - new networks can be added by implementing the client interface.
Verify result
type VerifyResult struct {
IsValid bool
InvalidReason string
Sender string
Timestamp int64
Extra map[string]interface{}
}Settle result
type SettleResult struct {
Success bool
TxHash string
Error string
NetworkId string
Block uint64
Sender string
Recipient string
Amount string
Asset string
Fees string
Extra map[string]interface{}
}Protocol Versioning
The current protocol version is 1. All requests and payloads must include "x402Version": 1. Future versions will be announced in the x402-go repository.
Further Reading
- Quickstart - send your first payment in minutes.
- Facilitator Introduction - how this server implements the protocol.
- API Reference - full
/verifyand/settleendpoint docs.