x402 Protocol Reference
HTTP 402 Payment Flow
The x402 protocol enables HTTP payments using blockchain transactions. Sigwei implements this protocol to monetize API access.
Standard Payment Flow
Initial Request: Client requests PayGate URL without payment
GET /abc123
Payment Required: Server responds with HTTP 402 and payment token
HTTP/1.1 402 Payment Required Content-Type: application/json { "x402": { "token": "payment_token_here", "amount": "0.01", "address": "0x742d35Cc6634C0532925a3b8c2414F4e456C10F4" } }
Payment Execution: Client creates blockchain payment using wallet
Payment Submission: Client retries request with payment proof
GET /abc123 X-Payment: <base64-encoded-payment-data>
Payment Verification: Server verifies signature and blockchain transaction
Access Granted: Client receives proxied response from target URL
Authentication + Payment Flow
For PayGates with requireAuth: true
:
Initial Request: Client requests without authentication
GET /xyz789
Authentication Required: Server returns 401
HTTP/1.1 401 Unauthorized { "error": { "type": "authentication", "code": "AUTH_REQUIRED", "message": "This route requires user authentication." } }
Authenticated Request: Client includes JWT token
GET /xyz789 Authorization: Bearer <jwt_token>
Payment Required: Server returns 402 with payment requirements
Final Request: Client includes both auth and payment
GET /xyz789 Authorization: Bearer <jwt_token> X-Payment: <payment_proof>
x402 Headers
Request Headers
X-Payment: <base64-encoded-payment-data>
Authorization: Bearer <jwt_token> // Optional, for auth-required PayGates
Response Headers
X-Payment-Response: <payment-confirmation-data> // Optional
X402-Version: 1
Content-Type: application/json
Payment Data Structure
The X-Payment
header contains base64-encoded JSON with payment information:
{
"x402Version": 1,
"scheme": "exact",
"network": "base-sepolia",
"payload": {
"signature": "0x1234567890abcdef...",
"authorization": {
"from": "0x742d35cc6634c0532925a3b8c2414f4e456c10f4",
"to": "0x9876543210fedcba...",
"value": "1000000", // Amount in USDC microdollars (1 USDC = 1,000,000)
"validAfter": "0",
"validBefore": "1735689600", // Unix timestamp
"nonce": "0xabcdef1234567890..." // 32-byte random nonce
}
}
}
Field Descriptions
x402Version
Protocol version (always 1)
scheme
Payment scheme (always "exact")
network
Blockchain network ("base-sepolia" or "base-mainnet")
signature
EIP-712 signature of the authorization
from
Payer's wallet address
to
Payment recipient address (from PayGate configuration)
value
Payment amount in USDC microdollars (6 decimals)
validAfter
Earliest valid timestamp (usually "0")
validBefore
Latest valid timestamp
nonce
Unique 32-byte identifier to prevent replay attacks
EIP-712 Typed Data Signature
Payments use EIP-712 structured signatures for security:
{
"domain": {
"name": "USD Coin",
"version": "2",
"chainId": 84532, // Base Sepolia
"verifyingContract": "0x036CbD53842c5426634e7929541eC2318f3dCF7e" // USDC contract
},
"types": {
"TransferWithAuthorization": [
{ "name": "from", "type": "address" },
{ "name": "to", "type": "address" },
{ "name": "value", "type": "uint256" },
{ "name": "validAfter", "type": "uint256" },
{ "name": "validBefore", "type": "uint256" },
{ "name": "nonce", "type": "bytes32" }
]
},
"primaryType": "TransferWithAuthorization",
"message": {
"from": "0x742d35cc6634c0532925a3b8c2414f4e456c10f4",
"to": "0x9876543210fedcba...",
"value": "1000000",
"validAfter": "0",
"validBefore": "1735689600",
"nonce": "0xabcdef1234567890..."
}
}
Network Configurations
Base Sepolia (Testnet)
Chain ID:
84532
USDC Contract:
0x036CbD53842c5426634e7929541eC2318f3dCF7e
RPC:
https://sepolia.base.org
Base Mainnet
Chain ID:
8453
USDC Contract:
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
RPC:
https://mainnet.base.org
JavaScript Implementation Example
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';
async function createPayment(paymentRequest, privateKey) {
const account = privateKeyToAccount(privateKey);
const walletClient = createWalletClient({
account,
chain: baseSepolia,
transport: http()
});
// Generate payment authorization
const authorization = {
from: account.address,
to: paymentRequest.address,
value: (parseFloat(paymentRequest.amount) * 1e6).toString(), // Convert to microdollars
validAfter: "0",
validBefore: Math.floor(Date.now() / 1000) + 3600, // 1 hour validity
nonce: "0x" + Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, '0')).join('')
};
// Sign with EIP-712
const signature = await walletClient.signTypedData({
domain: {
name: 'USD Coin',
version: '2',
chainId: 84532,
verifyingContract: '0x036CbD53842c5426634e7929541eC2318f3dCF7e'
},
types: {
TransferWithAuthorization: [
{ name: 'from', type: 'address' },
{ name: 'to', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'validAfter', type: 'uint256' },
{ name: 'validBefore', type: 'uint256' },
{ name: 'nonce', type: 'bytes32' }
]
},
primaryType: 'TransferWithAuthorization',
message: authorization
});
// Create x402 payment data
const paymentData = {
x402Version: 1,
scheme: "exact",
network: "base-sepolia",
payload: {
signature: signature,
authorization: authorization
}
};
// Return base64-encoded payment header
return btoa(JSON.stringify(paymentData));
}
// Usage with HTTP client
const paymentHeader = await createPayment(paymentRequest, "0xYOUR_PRIVATE_KEY");
const response = await fetch('/abc123', {
headers: {
'X-Payment': paymentHeader
}
});
Error Handling
Common payment-related errors:
// Invalid signature
{
"error": {
"type": "payment",
"code": "INVALID_SIGNATURE",
"message": "Payment signature verification failed"
}
}
// Insufficient amount
{
"error": {
"type": "payment",
"code": "INSUFFICIENT_AMOUNT",
"message": "Payment amount is less than required"
}
}
// Expired payment
{
"error": {
"type": "payment",
"code": "PAYMENT_EXPIRED",
"message": "Payment authorization has expired"
}
}
// Already used nonce
{
"error": {
"type": "payment",
"code": "NONCE_ALREADY_USED",
"message": "Payment nonce has already been used"
}
}
Client Libraries
For automatic x402 payment handling, use compatible HTTP clients:
JavaScript:
x402-axios
- Intercepts 402 responses and handles payments automaticallyPython:
x402-requests
- Python requests library with x402 supportGo: Manual implementation or x402-compatible HTTP transport
cURL: Manual payment header creation for testing
These libraries abstract away the complexity of payment creation and signature handling, making x402 integration seamless for developers.
Last updated