Merchant setup

Go-live checklist

What to set, check and put in front of the gateway before anyone else can reach it.

The demo binds everything to 127.0.0.1. Before the gateway is reachable by anyone else, work through this list.

Access

  • Set server.adminToken to a real secret
    This token protects /api/receipts, /api/events, /api/payment-attempts and /api/transactions, which expose payer addresses, amounts and settlement hashes, and POST /api/payment-attempts/:id/resolve, which records resolutions. Without it, these routes return 404 and you cannot read your ledger over HTTP.
  • Keep server.allowedOrigins minimal
    An explicit allowlist for browsers, empty by default. Agent traffic needs no entry.
  • Do not ship the admin token to a browser
    The demo dashboard inlines it via VITE_ADMIN_TOKEN, which makes it public to anyone who loads the page. Never point a real token at it.
  • Terminate TLS in front of the gateway
    Mandatory for ACP, whose bearer token is otherwise a shared secret in the clear, and for MPP, whose core draft forbids issuing challenges over plain HTTP.

Abuse controls

  • Add rate limiting at your edge
    The gateway has none. A free resource is an unauthenticated proxy to your backend at whatever rate a caller chooses.
  • Keep your backend's own authentication
    The gateway does not secure your API; its credentials go in backend.headers as ${VAR} references.
  • Review every backend URL
    There is no private-address blocklist. The gateway calls exactly what you configure.

Money

  • Confirm payTo is your wallet
    Compare the startup banner, /.well-known/agent-commerce and doctor, for every offer. A development address is refused on any public network. On Solana the wallet's USDC token account must exist; on NEAR the account needs a storage deposit on the token.
  • Use an authenticated facilitator on mainnet
    bearer needs no extra package; cdp requires the optional @coinbase/x402 peer and CDP's URL. An unauthenticated one requires allowUnauthenticatedFacilitator: true and is reported as WARN.
  • Check the facilitator lists every network
    Each offer's network must appear in the facilitator's /supported; otherwise that offer's health fails and so does readiness.
  • Use a dedicated RPC endpoint
    One per network. Public endpoints rate-limit, and their outages become your readiness failures.
  • Pick a payment flow per resource
    x402's default authorization flow calls your backend before settling, so a refused settlement leaves that work unpaid. Set paymentFlow: upfront, MPP's default, on resources whose side effects must follow payment.
  • Plan for reconciliation
    Settlement is final. Under upfront, a backend failure after payment is recorded without reversing the payment. A settlement with no verdict leaves no receipt. The gateway tries to record settlement-uncertain and any known transaction hash; failed writes can leave less evidence. Find unresolved purchases at GET /api/transactions?unresolved=true, check chain evidence with agent-commerce reconcile, or record an operator verdict when appropriate with agent-commerce resolve.
  • Give quote signing its own key
    If you enable ERC-8409 quotes, use a dedicated, unfunded key. Never reuse a merchant or buyer key. Anyone holding it can sign quotes as you. Restart the gateway after rotating the key; doctor checks the published issuer against your local config.
  • Know there is no commissioned audit
    No third-party audit covers the payment path in any release. Weigh that before putting production funds through it.

Operations

  • Back up the receipt database
    Receipts, the journal, AP2 holds, ACP claims and pending A2A tasks share one database in 2.6.0. Use agent-commerce backup, and test a restore. A deleted consumed mandate becomes spendable again. Run one gateway process per receipt database.
  • Point probes at /health and /ready
    /ready answers 503 while the store, an adapter, or a payment or authorization provider reports fail; a warn stays ready.
  • Run agent-commerce doctor --json after every deploy
    It exits non-zero on any failure.

The full threat model is in Security model.