Skip to main content

Quickstart

This guide will help you integrate x402 payments into your application.

Step 1: Choose Your Scheme

Not sure? Use escrow if you’re building AI agents or making frequent API calls. Use exact for simple one-off payments.

Environment Setup

Currently Base Sepolia only. The facilitator is live on Base Sepolia (testnet). Base Mainnet support coming soon.
EnvironmentChainNetwork IDStatus
TestnetBase Sepoliaeip155:84532✅ Live
ProductionBase Mainneteip155:8453🔜 Soon
Facilitator URL: https://facilitator.agentokratia.com

Installation

npm install @x402/core @agentokratia/x402-escrow

Test Your Setup (2 minutes)

Before integrating, verify everything works:
1

Get testnet USDC

You need testnet USDC on Base Sepolia for deposits:
  1. Get testnet ETH from Alchemy Faucet
  2. Get testnet USDC from Circle Faucet
USDC Contract (Base Sepolia): 0x036CbD53842c5426634e7929541eC2318f3dCF7e
2

Verify facilitator is accessible

curl https://facilitator.agentokratia.com/api/supported
Expected response (truncated):
{
  "kinds": [{ "scheme": "exact", ... }, { "scheme": "escrow", ... }],
  "extensions": ["agentokratia"],
  "signers": { "eip155:8453": ["0x..."] }
}
3

Get your API key (servers only)

If you’re protecting an API, get an API key from the Dashboard.
Deposit amounts: The default is 10000000 atomic units = 10USDC.Fortesting,try1000000(10 USDC. For testing, try `1000000` (1) to conserve testnet funds.

Supported Networks

NetworkChain IDCAIP-2 ID
Base Mainnet8453eip155:8453
Base Sepolia (testnet)84532eip155:84532
Use Base Sepolia for development. Testnet USDC is free from the faucets above.

Supported Wallets

Any wallet supporting EIP-712 typed data signing works with x402:
WalletStatusNotes
MetaMaskFully supportedBrowser extension + Mobile
Coinbase WalletFully supportedNative Base integration
RainbowFully supported
WalletConnect v2Fully supported400+ wallets
LedgerFully supportedVia MetaMask integration
Safe (Gnosis)PartialRequires multi-sig threshold
FrameFully supported
All wallets must support EIP-712 typed data signing, which is standard for modern wallets. No special wallet features required.

Prerequisites

Before starting, you’ll need:
Get an API key from the Dashboard by:
  1. Connecting your wallet via SIWE
  2. Creating a new API key in the dashboard
  3. Storing it securely (shown only once)
Note: Clients don’t need an API key - only servers protecting endpoints.
A viem WalletClient with an account and chain. Example setup:
// Browser (with wagmi)
import { useWalletClient } from 'wagmi';
const { data: walletClient } = useWalletClient();

// Node.js (with private key)
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const walletClient = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: base,
  transport: http(),
});
USDC on Base for payments. No approval needed - x402 uses ERC-3009 gasless signatures.

Exact Scheme Quickstart

The exact scheme is standard x402 - one signature per request.

Client (exact)

import { useWalletClient } from 'wagmi';
import { wrapFetchWithPayment } from '@x402/fetch';
import { x402Client } from '@x402/core/client';

const { data: walletClient } = useWalletClient();

if (walletClient) {
  const x402 = new x402Client(walletClient);
  const paidFetch = wrapFetchWithPayment(fetch, x402);

  // User signs each request
  const response = await paidFetch('https://api.example.com/premium');
}
The exact scheme requires user signature per request - best for browser dApps where users approve each payment.

Server (exact)

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

const facilitator = new HTTPFacilitatorClient({
  url: process.env.FACILITATOR_URL!,
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    supported: {},
  }),
});

const x402 = new x402ResourceServer(facilitator);

app.use(paymentMiddleware({
  'GET /api/premium': {
    accepts: {
      scheme: 'exact',
      price: '$0.10',
      network: 'eip155:8453',
      payTo: process.env.PAYMENT_ADDRESS!,
    },
  },
}, x402));

app.get('/api/premium', (req, res) => {
  res.json({ data: 'Premium content' });
});

Escrow Scheme Quickstart

The escrow scheme enables session-based payments - sign once, unlimited calls.

Client (escrow)

import { useWalletClient } from 'wagmi';
import { createEscrowFetch } from '@agentokratia/x402-escrow/client';

const { data: walletClient } = useWalletClient();

if (walletClient) {
  const { fetch: escrowFetch } = createEscrowFetch(walletClient, {
    depositAmount: '10000000', // $10 USDC deposit
    storage: 'localStorage',   // Persist sessions across reloads
  });

  // First call: signs once, creates session
  const response1 = await escrowFetch('https://api.example.com/premium');

  // Subsequent calls: instant, no signature needed
  const response2 = await escrowFetch('https://api.example.com/premium');
}
Sign once, pay forever: Users sign a single ERC-3009 authorization, then make unlimited API calls with zero additional signatures or gas.

What Happens Automatically

  1. First request - Signs ERC-3009, creates session, stores session.token
  2. Subsequent requests - Uses stored token (instant, no signature)
  3. Session expired - Automatically creates new session
  4. Insufficient balance - Creates new session with fresh deposit

Session Control

// Force new session (e.g., when user wants fresh deposit)
await escrowFetch(url, { session: 'new' });

// Use specific session
await escrowFetch(url, { session: 'session-id-here' });

Server (escrow)

import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
import { paymentMiddleware } from '@x402/express';
import { EscrowScheme } from '@agentokratia/x402-escrow/server';

const facilitator = new HTTPFacilitatorClient({
  url: process.env.FACILITATOR_URL!,
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    supported: {},
  }),
});

// Register escrow scheme
const x402 = new x402ResourceServer(facilitator)
  .register('eip155:8453', new EscrowScheme());

app.use(paymentMiddleware({
  'GET /api/premium': {
    accepts: {
      scheme: 'escrow',
      price: '$0.01',
      network: 'eip155:8453',
      payTo: process.env.PAYMENT_ADDRESS!,
    },
  },
}, x402));

app.get('/api/premium', (req, res) => {
  res.json({ data: 'Premium content' });
});

Accept Both Schemes

Servers can accept both schemes, letting clients choose:
const x402 = new x402ResourceServer(facilitator)
  .register('eip155:8453', new EscrowScheme());

app.use(paymentMiddleware({
  'GET /api/premium': {
    accepts: [
      { scheme: 'escrow', price: '$0.01', network: 'eip155:8453', payTo: '0x...' },
      { scheme: 'exact', price: '$0.01', network: 'eip155:8453', payTo: '0x...' },
    ],
  },
}, x402));

Environment Variables

.env
# Facilitator URL
FACILITATOR_URL=https://facilitator.agentokratia.com

# Your API key (from dashboard)
X402_API_KEY=x402_...

# Your receiving wallet address
PAYMENT_ADDRESS=0xYourWalletAddress

x402 Headers

The protocol uses these HTTP headers (handled automatically by the SDK):
HeaderDirectionContent
PAYMENT-REQUIREDServer → ClientPayment requirements (base64 JSON)
PAYMENT-SIGNATUREClient → ServerPayment payload (base64 JSON)
PAYMENT-RESPONSEServer → ClientSettlement result (base64 JSON)

Next Steps