Developer & Agent Guide

Integrate & test x402 paid endpoints

1. What is x402?

x402 is an open protocol for API monetization. Each paid request requires a USDC micro-payment on Base to reward recipients and prevent spam.

Flow Diagram

  1. Call paid endpoint (e.g., /api/v1/scan).
  2. Receive 402 Challenge (USDC amount + payTo).
  3. Transfer USDC to payTo on Base L2.
  4. Retry request with TX hash in x-payment-tx-hash header.

2. API Endpoints

EndpointMethodPriceDescription
/api/v1/scanPOST$0.02 USDCScan token holders on supported chains.
/api/v1/proofsPOST$0.01 USDCUpload Merkle proofs for campaign claims.
/api/v1/inboxPOST$0.01 USDCRetrieve message lists & metadata.
Sample 402 Challenge Payload
{
  "x402Version": 2,
  "resource": {
    "url": "https://ting.openads.world/api/v1/scan",
    "description": "Ting Developer API - Scan token holders"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "20000",
      "payTo": "0x3131e50f166765989871273d9cd7e7D0557e5253",
      "maxTimeoutSeconds": 60
    }
  ]
}

3. SDK Integration (Node.js)

Use @x402/fetch and @x402/evm to intercept challenges and complete payments automatically.

JavaScript Integration Code
const { createPublicClient, http } = require('viem');
const { privateKeyToAccount } = require('viem/accounts');
const { base } = require('viem/chains');
const { x402Client, wrapFetchWithPayment } = require('@x402/fetch');
const { ExactEvmScheme, toClientEvmSigner } = require('@x402/evm');

// 1. Initialize wallet and RPC
const account = privateKeyToAccount(process.env.TING_PRIVATE_KEY);
const publicClient = createPublicClient({
  chain: base,
  transport: http('https://mainnet.base.org')
});

// 2. Setup x402 signer client
const evmSigner = toClientEvmSigner(account, publicClient);
const client = new x402Client()
  .register('eip155:8453', new ExactEvmScheme(evmSigner));

// 3. Wrap fetch handler
const fetchWithPay = wrapFetchWithPayment(fetch, client);

// 4. Run paid request
async function scan() {
  const res = await fetchWithPay('https://ting.openads.world/api/v1/scan', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      token: '0xFDFfb411C4A70AA7C95D5C981a6Fb4Da867e1111',
      chain: 'bnb',
      limit: 100
    })
  });
  console.log(await res.json());
}
scan().catch(console.error);

4. Manual Payments (cURL)

Or manually send USDC and pass the TX hash in the header.

cURL Request Example
curl -X POST https://ting.openads.world/api/v1/scan \
  -H "Content-Type: application/json" \
  -H "x-payment-tx-hash: <USDC_transfer_tx_hash_on_base>" \
  -d '{"token": "0xFDFfb411C4A70AA7C95D5C981a6Fb4Da867e1111", "chain": "bnb", "limit": 100}'

5. Important Rules & Gotchas

BNB Chain Holder Scanning (Rule 5)

No public Blockscout for BNB Chain. Direct scans are prohibited. Route queries via Moralis proxy (/api/scan?chain=bnb&...).

Minimum Reward Amount

When creating a campaign, the reward per recipient must be at least 0.05 USDC (or USDT on BNB Chain). Calls to /api/v1/proofs with rewards lower than this threshold will fail validation with a 400 Bad Request error.

Double-Spend Prevention

TX hashes cannot be reused. Reuse returns 402 Transaction hash already used.

Coinbase Wallet CLI ("awal")

If prompted during npx awal x402 pay, run npx awal show to authenticate in the UI.