Skip to content

Choosing a facilitator

A facilitator sits between your API and the chain: it verifies payment payloads and settles them on-chain. You configure a base URL and call its POST /verify and POST /settle endpoints from your server middleware.

TallyPay does not replace your facilitator — it instruments your app and correlates events. You can change facilitators without changing TallyPay’s role.

CriterionQuestions to ask
NetworksBase, Arbitrum, Polygon, Solana, Stellar? Which match your users and liquidity?
AssetsUSDC only, or others? Mainnet + testnet faucets for development?
API shapeStandard POST /verify + POST /settle with JSON, or custom SDK wrapper?
Latency & reliabilityp95 for verify/settle? Incident history?
Compliance & custodyWho holds keys? What jurisdictions? (Legal review for your product.)
PricingPer-transaction fee? Free tier? Compare vs building in-house chain plumbing.
Chain coverageSingle-chain vs multi-chain? Does it auto-route based on the payment network?
FacilitatorBase URLNetworksNotes
Coinbase CDPhttps://x402-facilitator.cdp.coinbase.comBase, Ethereum, Arbitrum, PolygonFree tier. Widely used. Docs.
thirdwebVia SDK (facilitator() function)26+ EVM chainsIntegrated into the thirdweb SDK. HTTP API available. Docs.
xpayhttps://facilitator.xpay.shMultiple EVM chainsExposes GET /health, GET /supported, POST /verify, POST /settle. Docs.
Self-hostedYour own URLWhatever you supportFull control, full operational burden. Implement the /verify + /settle contract yourself.

Always verify endpoint URLs and payload formats against the facilitator’s current documentation before deploying. URLs and supported chains change.

@tallypay/server expects the following standard endpoints:

POST {facilitatorUrl}/verify

  • Body: raw payment signature string (from the client’s payment-signature header).
  • Response: { "valid": true } or { "valid": false, "reason": "..." }.
  • Timeout: 10 seconds.

POST {facilitatorUrl}/settle

  • Body: same as verify.
  • Response: { "settled": true, "txHash": "0x..." } or { "settled": false }.
  • Timeout: 30 seconds.

If your facilitator uses different paths, response shapes, or authentication, write a thin HTTP proxy that normalizes to this contract.

Some facilitators (e.g. xpay) expose a GET /supported endpoint returning the networks and assets they handle. Useful for dynamic configuration or multi-facilitator routing:

{
"networks": ["eip155:8453", "eip155:1", "eip155:42161"],
"assets": ["USDC"],
"x402Version": 2
}
  • Use testnets (Base Sepolia: eip155:84532) and faucet USDC while integrating. Keep separate facilitator URLs and merchant addresses.
  • Log x-trace-id from server responses in your own observability stack for correlation with TallyPay traces.
  • Some facilitators have sandbox modes or testnet-specific URLs — check their docs.
import { tallypay } from "@tallypay/server/express";
app.use("/api/premium", tallypay({
facilitatorUrl: "https://x402-facilitator.cdp.coinbase.com",
payTo: "0xYourAddress",
price: "10000",
network: "eip155:8453",
asset: "USDC",
}));

The middleware handles the verify → settle flow against whichever facilitator URL you provide.