Public networks

Base mainnet (PayAI)

Real funds through a public facilitator that takes no credential.

Settles x402 v2 exact payments on Base through PayAI's public facilitator, with auth.type: none. PayAI's pricing guide says ordinary exact payments need no API key within the free credit allowance. Credits are counted per receiving wallet for its lifetime; shared hosts and IPs also draw from a shared pool, which may run out sooner. Beyond the allowance, PayAI requires credits and a key. The gateway still needs its x402 peers, but not @coinbase/x402.

Check what PayAI supports before spending real USDCbash
node -e "fetch('https://facilitator.payai.network/supported').then(r=>r.json())
  .then(d=>console.log(d.kinds.filter(k=>k.network==='eip155:8453')))"

Confirm the output includes protocol v2 and the exact scheme.

examples/base-mainnet-payai/config.yamlyaml
version: 1

merchant:
  id: base-mainnet-payai-example
  name: Base Mainnet (PayAI) Example
  publicBaseUrl: ${GATEWAY_PUBLIC_BASE_URL:-http://localhost:8080}

server:
  port: ${GATEWAY_PORT:-8080}
  host: 0.0.0.0
  allowedOrigins: []

storage:
  receipts:
    driver: sqlite
    path: ${RECEIPT_STORE_PATH:-./data/receipts.sqlite}

protocols:
  http:
    enabled: true
  mcp:
    enabled: true
    mountPath: /mcp

resources:
  premium_report:
    name: Premium Report
    description: One paid endpoint, settled in USDC on Base.
    input:
      type: object
      properties: {}
      additionalProperties: false
    backend:
      type: http
      method: GET
      url: ${MERCHANT_API_BASE_URL:-http://localhost:3000}/api/report
      timeoutMs: 10000
    pricing:
      type: fixed
      amount: "0.01"
      currency: USDC
    expose: [http, mcp]
    payments: [x402]

payments:
  x402:
    enabled: true
    network: eip155:8453
    rpcUrl: ${X402_RPC_URL:-https://base.drpc.org}
    asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    assetName: "USD Coin"
    assetVersion: "2"
    assetDecimals: 6
    payTo: ${MERCHANT_WALLET}
    maxTimeoutSeconds: 600
    # required, and required to be `true`. Mainnet is never a default
    allowMainnet: ${ALLOW_X402_MAINNET}
    # A separate decision from allowMainnet: every payment authorization goes
    # to PayAI without credentials, and PayAI applies its own limits
    allowUnauthenticatedFacilitator: true
    facilitator:
      mode: remote
      url: https://facilitator.payai.network
      auth:
        type: none

Two acknowledgments, not one

yaml
allowMainnet: true                     # I meant to use real money
allowUnauthenticatedFacilitator: true  # I accept THIS counterparty

Neither implies the other, and dropping either fails config loading:

console
FAIL  CONFIG_INVALID: payments.x402: no credential is configured for facilitator https://facilitator.payai.network on mainnet. Set payments.x402.allowUnauthenticatedFacilitator: true to accept anonymous access and the facilitator's limits, or configure facilitator.auth.
      details: {"path":"payments.x402.allowUnauthenticatedFacilitator"}

doctor reports it as WARN, not a pass, for as long as it stays this way.

What you are exposed to

Not your money: an EIP-3009 authorization names its recipient, amount and chain, so the facilitator can broadcast exactly that transfer or nothing. At risk: privacy (it sees each authorization, with the payer, amount and timing) and availability — once the payTo wallet's allowance or the shared pool is exhausted, unauthenticated paid calls fail closed. For sustained use, choose a facilitator the gateway can authenticate to (bearer or cdp), or run your own.

Run it

bash
ALLOW_X402_MAINNET=true MERCHANT_WALLET=0xYourWallet \
  npm run agent-commerce -- validate --config examples/base-mainnet-payai/config.yaml

# to actually settle: each successful x402 run spends real USDC (default 0.01)
export ALLOW_X402_MAINNET=true
export X402_SMOKE_TARGETS=base
export X402_MAINNET_BUYER_PRIVATE_KEY=0x...   # funded with USDC on Base
export X402_MAINNET_MERCHANT_ADDRESS=0x...
export X402_FACILITATOR_URL=https://facilitator.payai.network
npm run test:mainnet

The smoke test reads the USDC Transfer from the transaction receipt on Base to confirm settlement; see smoke tests.

Source: examples/base-mainnet-payai