Skip to content
This repository was archived by the owner on Apr 30, 2026. It is now read-only.

Latest commit

 

History

History
172 lines (125 loc) · 5.46 KB

File metadata and controls

172 lines (125 loc) · 5.46 KB

x402 Payment Protocol

How Snakey uses x402 for USDC game entry fees ($0.25 USDC; set via GAME_ENTRY_FEE, same on testnet and mainnet).


What is x402?

x402 revives the HTTP 402 "Payment Required" status code for blockchain micropayments. Developed by Coinbase and Cloudflare, launched May 2025.

Key idea: Client requests resource → Server returns 402 → Client signs payment → Client retries → Server verifies and delivers.


Payment Flow

Agent                     Snakey Server              Facilitator           Blockchain
  │                            │                          │                     │
  │─── POST /join ────────────▶│                          │                     │
  │                            │                          │                     │
  │◀── 402 + payment details ──│                          │                     │
  │    (price, network, payTo) │                          │                     │
  │                            │                          │                     │
  │ (Agent signs EIP-712 msg)  │                          │                     │
  │                            │                          │                     │
  │─── POST /join + signature ▶│                          │                     │
  │                            │─── POST /verify ────────▶│                     │
  │                            │                          │── USDC transfer ───▶│
  │                            │◀── settlement OK ────────│                     │
  │◀── 200 OK (joined queue) ──│                          │                     │

Our Configuration

Environment Variables:

X402_WALLET_ADDRESS=0x...      # Your wallet receiving payments
X402_NETWORK=eip155:84532      # Network (see below)

Networks:

Network X402_NETWORK Facilitator USDC
Testnet eip155:84532 x402.org/facilitator Free (faucet)
Mainnet eip155:8453 api.cdp.coinbase.com/platform/v2/x402 Real

Facilitator URL auto-detected based on network.


npm Packages

Package Purpose We Use
@x402/core Types, client, facilitator
@x402/express Server middleware
@x402/evm EVM blockchain support
@x402/fetch Client auto-payment For SDK

How We Use It

Server (src/server.js):

import { paymentMiddleware, x402ResourceServer } from '@x402/express';
import { ExactEvmScheme } from '@x402/evm/exact/server';
import { HTTPFacilitatorClient } from '@x402/core/server';

const x402Server = new x402ResourceServer(
  new HTTPFacilitatorClient({ url: FACILITATOR_URL })
)
.register('eip155:84532', new ExactEvmScheme())  // Testnet
.register('eip155:8453', new ExactEvmScheme());  // Mainnet

app.use(paymentMiddleware({
  'POST /join': {
    accepts: {
      scheme: 'exact',
      price: '$0.25',
      network: X402_NETWORK,
      payTo: X402_WALLET_ADDRESS
    }
  }
}, x402Server));

Settlement observer (not middleware hooks): @x402/express v2.2.0 does not expose afterSettlement / onVerificationFailure hooks — the 3rd positional arg is paywallConfig. Snakey uses an explicit res.on('finish') observer (attachSettlementObserver in src/server.js) to:

  • Record settled payments to the payments table on HTTP 200 (decoding X-Payment-Response)
  • Roll back queue + jackpot contribution on HTTP 402 (settlement failure)
  • Track payer wallet for verification

HTTP Headers

402 Response (Server → Client):

HTTP/1.1 402 Payment Required
X-Payment-Required: [{"scheme":"exact","price":"$0.25","network":"eip155:84532","payTo":"0x..."}]

Retry Request (Client → Server):

POST /join
X-Payment: <base64-encoded-signed-payment>

For Agents

Use @x402/fetch to auto-handle payments:

import { wrapFetchWithPayment } from '@x402/fetch';
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';

const client = new x402Client();
registerExactEvmScheme(client, { signer: yourWallet });

const fetch402 = wrapFetchWithPayment(fetch, client);

// Automatically handles 402 → sign → retry
const response = await fetch402('https://api.snakey.ai/join', {
  method: 'POST',
  body: JSON.stringify({ playerId, displayName, walletAddress })
});

Testnet Faucets

Get free testnet tokens:

  • ETH (gas): coinbase.com/faucets/base-ethereum-sepolia-faucet
  • USDC: faucet.circle.com (select Base Sepolia)

Common Issues

Problem Fix
402 in development Set NODE_ENV=development to bypass
Network mismatch Check X402_NETWORK matches facilitator
Payment not recognized Verify wallet has USDC on correct network
"Payment required" loop Check signature, may need fresh wallet nonce

Security

  • Payments verified by facilitator before settlement
  • On-chain USDC transfer (irreversible)
  • Wallet ownership verified via EIP-712 signature
  • Rate limited: 3 joins per wallet per hour

Links