Instant Payments with x402
x402 is Coinbase's stateless HTTP 402 payment protocol. Unlike MPP's session-based approach, x402 uses a simple three-header flow: the server returns 402 with payment requirements, the client signs a payment payload and retries, and the server verifies and fulfills the request. No sessions, no state — the fastest path to machine-to-machine payments.
Prerequisites
- Wallet with TNZO balance
- Registered identity (TDIP)
- Basic understanding of HTTP headers and REST APIs
- cURL or HTTP client library
What is x402?
x402 is a stateless HTTP 402 payment protocol created by Coinbase for seamless machine-to-machine payments:
- Stateless: No session management or server-side state tracking
- Three-header flow: PAYMENT-REQUIRED → PAYMENT-SIGNATURE → PAYMENT-RESPONSE
- HTTP 402 native: Uses standard HTTP status code for payment required
- Multi-asset: Supports USDC, USDT, TNZO, and other ERC-20 tokens
- Ideal for discrete payments: One-shot API calls, data purchases, resource access
- Coinbase compatible: Integrates with Coinbase Agentic Wallets and CDP SDK
The x402 Flow
x402 eliminates the complexity of session-based payment protocols with a simple four-step flow:
- Client requests a resource — Standard HTTP GET/POST request
- Server responds with HTTP 402 — Includes payment requirements in
X-PAYMENT-REQUIREDheader - Client constructs and signs payment payload — Creates JSON payload with amount, asset, recipient, chain ID, and nonce; signs with wallet
- Client retries with payment signature — Includes signed payload in
X-PAYMENT-SIGNATUREheader - Server verifies and settles — Validates signature, settles on-chain, and returns resource with receipt in
X-PAYMENT-RESPONSEheader
Step 1: Create an x402 Payment Challenge
Use the create_payment_challenge MCP tool to generate a payment challenge for a resource:
curl -s -X POST "https://mcp.tenzro.network/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: $(uuidgen)" \
-d '{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "create_payment_challenge",
"arguments": {
"protocol": "x402",
"resource": "/api/data",
"amount": 500000,
"asset": "USDC",
"recipient": "0x0000000000000000000000000000000000000001"
}
}
}'Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": {
"challenge_id": "x402_ch_a1b2c3d4e5f6",
"protocol": "x402",
"resource": "/api/data",
"amount": 500000,
"asset": "USDC",
"recipient": "0x0000000000000000000000000000000000000001",
"chain_id": 1337,
"payment_required_header": "{\"amount\":500000,\"asset\":\"USDC\",\"recipient\":\"0x0000000000000000000000000000000000000001\",\"chain\":1337,\"facilitator\":{\"name\":\"Tenzro Network\",\"url\":\"https://api.tenzro.network\"}}",
"facilitator": {
"name": "Tenzro Network",
"url": "https://api.tenzro.network",
"settlement_endpoint": "https://api.tenzro.network/api/x402/settle"
},
"created_at": "2026-03-24T10:30:00Z",
"expires_at": "2026-03-24T11:30:00Z"
}
}
],
"isError": false
}
}The response includes the payment_required_header content that would be sent in the HTTP 402 response, along with facilitator information for settlement.
Step 2: Construct and Sign Payment Payload
The client must construct a payment payload matching the requirements and sign it with their wallet private key. The payload includes:
payer— Client's wallet addressamount— Payment amount in smallest unit (e.g., USDC cents)asset— Asset symbol (USDC, USDT, TNZO)recipient— Payment recipient addresschain— Chain ID (1337 for Tenzro Ledger)nonce— Unique nonce for replay protectionsignature— ECDSA signature over the payload
Step 3: Verify Payment
Use the verify_payment MCP tool to verify the signed payment and settle on-chain:
curl -s -X POST "https://mcp.tenzro.network/mcp" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: $(uuidgen)" \
-d '{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "verify_payment",
"arguments": {
"challenge_id": "x402_ch_a1b2c3d4e5f6",
"protocol": "x402",
"payer_did": "did:tenzro:human:550e8400-e29b-41d4-a716-446655440000",
"payer_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"amount": 500000,
"asset": "USDC",
"signature": "0x1234567890abcdef..."
}
}
}'Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"content": [
{
"type": "text",
"text": {
"verified": true,
"receipt": {
"payment_id": "x402_pay_f6e5d4c3b2a1",
"challenge_id": "x402_ch_a1b2c3d4e5f6",
"payer_did": "did:tenzro:human:550e8400-e29b-41d4-a716-446655440000",
"payer_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"amount": 500000,
"asset": "USDC",
"recipient": "0x0000000000000000000000000000000000000001",
"settlement_tx": "0xaabbccddeeff...",
"settled_at": "2026-03-24T10:32:15Z",
"payment_response_header": "{\"payment_id\":\"x402_pay_f6e5d4c3b2a1\",\"settlement_tx\":\"0xaabbccddeeff...\",\"settled_at\":\"2026-03-24T10:32:15Z\"}"
}
}
}
],
"isError": false
}
}The receipt includes the settlement transaction hash and the payment_response_header content that would be returned in the HTTP 200 response.
The HTTP 402 Headers
x402 uses three custom HTTP headers to implement the payment flow:
1. X-PAYMENT-REQUIRED (Server → Client)
Sent by the server in the HTTP 402 response. Contains JSON with payment requirements:
amount— Payment amount requiredasset— Asset symbol (USDC, USDT, TNZO)recipient— Payment recipient addresschain— Chain ID for settlementfacilitator— Facilitator name and settlement endpoint
2. X-PAYMENT-SIGNATURE (Client → Server)
Sent by the client when retrying the request. Contains JSON with signed payment authorization:
payer— Client's wallet addressamount— Payment amountasset— Asset symbolrecipient— Payment recipientchain— Chain IDnonce— Unique noncesignature— ECDSA signature over payload
3. X-PAYMENT-RESPONSE (Server → Client)
Sent by the server in the HTTP 200 response after successful payment. Contains JSON with receipt:
payment_id— Unique payment identifiersettlement_tx— On-chain transaction hashsettled_at— Settlement timestamp (ISO 8601)
Example HTTP exchange:
# 1. Client makes initial request
GET /api/data HTTP/1.1
Host: api.example.com
# 2. Server responds with 402 Payment Required
HTTP/1.1 402 Payment Required
X-PAYMENT-REQUIRED: {"amount":500000,"asset":"USDC","recipient":"0x0000000000000000000000000000000000000001","chain":1337,"facilitator":{"name":"Tenzro Network","url":"https://api.tenzro.network"}}
Content-Length: 0
# 3. Client retries with payment signature
GET /api/data HTTP/1.1
Host: api.example.com
X-PAYMENT-SIGNATURE: {"payer":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","amount":500000,"asset":"USDC","recipient":"0x0000000000000000000000000000000000000001","chain":1337,"nonce":"12345","signature":"0x1234567890abcdef..."}
# 4. Server verifies, settles, and responds with data + receipt
HTTP/1.1 200 OK
X-PAYMENT-RESPONSE: {"payment_id":"x402_pay_f6e5d4c3b2a1","settlement_tx":"0xaabbccddeeff...","settled_at":"2026-03-24T10:32:15Z"}
Content-Type: application/json
{"data": "Your requested content"}Client Integration
The Tenzro TypeScript SDK provides an X402Client that automatically handles the payment flow:
import { X402Client } from '@tenzro/sdk';
const client = new X402Client({
wallet: yourWallet,
identity: 'did:tenzro:human:550e8400-e29b-41d4-a716-446655440000',
});
// Automatic HTTP 402 handling
const response = await client.fetch('https://api.example.com/data');
// Client automatically:
// 1. Receives 402 response
// 2. Constructs payment payload
// 3. Signs with wallet
// 4. Retries with X-PAYMENT-SIGNATURE header
// 5. Returns final response with data + receipt
console.log('Data:', await response.json());
console.log('Payment receipt:', response.headers.get('X-PAYMENT-RESPONSE'));Server Integration
The Tenzro TypeScript SDK also provides an X402PaymentServer for accepting payments:
import { X402PaymentServer } from '@tenzro/sdk';
const paymentServer = new X402PaymentServer({
recipient: '0x0000000000000000000000000000000000000001',
chainId: 1337,
facilitator: {
name: 'Tenzro Network',
url: 'https://api.tenzro.network',
},
});
// Express middleware
app.get('/api/data', async (req, res) => {
const paymentResult = await paymentServer.verifyPayment(req, {
amount: 500000,
asset: 'USDC',
resource: '/api/data',
});
if (!paymentResult.verified) {
// Send 402 with payment requirements
return paymentServer.sendPaymentRequired(res, {
amount: 500000,
asset: 'USDC',
});
}
// Payment verified, send data + receipt
res.setHeader('X-PAYMENT-RESPONSE', JSON.stringify(paymentResult.receipt));
res.json({ data: 'Your requested content' });
});x402 vs MPP: When to Use Which
Use x402 for:
- Discrete API calls — Single-request operations like data queries, file downloads
- One-shot data purchases — Market data, reports, documents
- Simple integrations — Minimal implementation complexity, no session management
- Stateless services— RESTful APIs that don't maintain client state
- Coinbase ecosystem — Services using Coinbase Agentic Wallets or CDP SDK
Use MPP for:
- Streaming services — Video, audio, real-time data feeds
- Per-token billing — AI inference, token-based API usage
- Session-based interactions — Long-running conversations, multi-request workflows
- Micropayments — Sub-cent incremental payments with vouchers
- Stripe ecosystem— Services using Stripe's Machine Payments Protocol
Both protocols enforce TDIP delegation scopes and support identity-bound payments. Choose based on your use case and integration requirements.
Integration with Coinbase
x402 is fully compatible with Coinbase Agentic Wallets. AI agents using Coinbase's CDP SDK can seamlessly pay for Tenzro Network services using the same x402 flow. The protocol supports Coinbase's Base network (chain ID 8453) as well as Tenzro Ledger (chain ID 1337), enabling cross-chain payment interoperability. Agents can use USDC on Base to pay for AI inference or TEE services on Tenzro, with automatic settlement via the configured facilitator.
Security Considerations
- Signature verification: Always verify ECDSA signatures before settlement
- Nonce tracking: Prevent replay attacks by tracking used nonces
- Amount validation: Ensure payment amount matches requirements exactly
- Chain ID verification: Reject payments for incorrect chains
- Delegation scope enforcement: Verify TDIP delegation scopes allow the payment protocol, amount, and chain
- Expiration checking: Reject stale payment requests beyond expiration time
What's Next?
- Session-based payments with MPP — Learn the session-based Machine Payments Protocol
- Build an AI payment agent — Create an autonomous agent that pays for services
- Payment Protocols Documentation — Deep dive into MPP, x402, and Tempo integration
- TDIP Documentation — Understand delegation scopes and payment authorization
Ready to Accept Payments?
Explore the Tenzro TypeScript SDK for production-ready x402 client and server implementations, or integrate with Coinbase CDP SDK for seamless agent-to-agent payments.