PayAI x402 Facilitator — developer reference

Everything an agent or a developer needs to call this API, served from the API's own origin. Machine-readable equivalents: OpenAPI 3.1, llms.txt, Markdown.

What this API does

This origin is the PayAI x402 facilitator. It implements the facilitator role of the x402 protocol: it verifies signed stablecoin payment payloads and settles them on-chain, so a resource server can charge per request without touching a wallet, an RPC node, or a private key.

x402 revives the HTTP 402 Payment Required status code. A server answers an unpaid request with 402 and machine-readable payment terms, the client signs a stablecoin payment, and the facilitator verifies and settles it. No accounts, no API keys, no card on file, no human in the loop.

The base URL for every endpoint below is https://facilitator.payai.network. A complete OpenAPI 3.1 description is served at /openapi.json.

When to call it

  • You received an HTTP 402 Payment Required response and need to check whether a signed payment is valid before serving a resource — call POST /verify.
  • You have verified a payment and want the funds moved on-chain — call POST /settle.
  • You need to know which chains, schemes, and protocol versions are live right now — call GET /supported.
  • You want to discover services an agent can pay for — call GET /discovery/resources.

This facilitator settles stablecoin micropayments over HTTP. It is not a payment processor for consumer checkout: no card payments, no fiat payouts, no bank transfers, no subscription billing, and it never custodies merchant balances.

Endpoints

Method and pathWhat it does
GET /healthLiveness probe. Returns 200 while the facilitator is accepting traffic.
GET /supportedEvery (x402 version, scheme, network) combination that is live right now, plus the fee-payer and facilitator addresses that sponsor gas.
GET /verifySelf-describing hint: names the endpoint and its expected request body.
POST /verifyVerify a signed payment against its payment requirements. Does not move funds.
GET /settleSelf-describing hint for the settle endpoint.
POST /settleSettle a payment on-chain. Idempotent: re-submitting an identical body returns the original outcome rather than paying twice.
GET /discovery/resourcesThe PayAI Bazaar catalog of x402-payable HTTP endpoints and MCP tools, with payment terms and, where published, input and output schemas. Paginated by limit and offset.
GET /discovery/statsAggregate catalog and settlement statistics.
GET /discovery/resources/{resource}/statsSettlement statistics for one catalog resource.
GET /listDeprecated. Redirects (308) to /discovery/resources.

Authentication

Every GET endpoint is public and unauthenticated. POST /verify and POST /settle take an optional Authorization: Bearer <api-key> for credit accounting, per-account settlement lanes, and analytics attribution. Without a key you are served on the free tier. Keys come from the merchant portal.

curl -s https://facilitator.payai.network/supported

curl -s -X POST https://facilitator.payai.network/verify \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <api-key>' \
  -d '{"x402Version":1,"paymentPayload":{...},"paymentRequirements":{...}}'

Error model

Errors are always JSON, never an HTML page. Two shapes exist, and which one you get depends on the endpoint.

POST /verify and POST /settle return the x402 response shape even on a non-2xx status, because the x402 client SDKs parse the body regardless of status code:

  • /verify{ isValid: false, invalidReason, invalidMessage }
  • /settle{ success: false, errorReason, errorMessage, transaction, network, payer }

Every other endpoint, every unknown path, and every unhandled failure returns RFC 9457 problem details with Content-Type: application/problem+json:

{
  "type": "https://facilitator.payai.network/developers#not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "No resource is served at GET /no-such-path."
}

Treat errorReason: "settlement_pending" on /settle as unresolved rather than failed: the payment may still land. Re-submit the identical body to poll for the final outcome — idempotency makes that safe.

POST /settle also accepts an optional Idempotency-Key header. A key is bound to the first request body it is used with for 24 hours, even while the outcome is unresolved: same-body retries replay a recorded terminal response with Idempotency-Replayed: true, reuse with a different body returns 422 regardless of outcome state, and concurrent same-body use returns 409.

settlement_pending, duplicate_settlement, 429, and 5xx outcomes are never cached, so a retry can continue polling instead of replaying an unresolved result. Terminal responses are retained for 24 hours, and signed-payload idempotency protects every settlement whether or not the header is present.

Problem type: not-found

No route is served at the requested path. Check the endpoint table above; note that there is no /v1/ prefix. Returned as 404.

Problem type: bad-request

The request could not be parsed — most often a body that is not valid JSON. Returned as 400. On /verify and /settle this arrives in the x402 response shape instead, with reason invalid_payload.

Problem type: internal-server-error

The facilitator failed to handle the request. The response carries no internal detail by design; retry with backoff, and quote the time of the request when contacting support. Returned as 500.

Versioning

This API is versioned by the x402 protocol version it speaks, not by a URL path segment and not by a version request header. There is no /v1/ prefix, and sending one will 404.

Every request carries x402Version (1 or 2) in its body, and the response echoes the version it was handled as. GET /supported advertises which (version, scheme, network) combinations are live: v1 uses short network names such as base and solana, v2 uses CAIP-2 identifiers such as eip155:8453. Both versions are served from the same paths, so an integration pins a version by what it sends, not by what it calls.

A payment kind is withdrawn by disappearing from GET /supported before the endpoints stop accepting it, so a client that polls /supported sees a removal coming. Breaking changes to request or response shapes arrive as a new x402Version; existing versions keep working until they leave /supported.

Rate limits

Throughput is limited per client IP at the edge, split into three buckets so an expensive settlement cannot starve the cheap reads that sit inside every paid call. Exceeding a bucket is rejected before the request reaches the API.

PolicyApplies toRequests per second, per IP
settlePOST /settle100
payments-read/verify, /supported200
discovery/discovery/* and all other paths25

Each response carries a RateLimit-Policy header naming the bucket that governs the path you called. The budget is enforced per ingress replica, so it is a floor rather than an exact ceiling.

No RateLimit header reporting remaining budget is emitted, because the limiter runs at the edge and the API is not told how much of your budget is left. Back off on the response status, not on a header countdown.

Separately from request rate, the free tier is capped by total settlements. Exhausting it returns HTTP 403 with errorReason beginning free_tier_exhausted; buy credits at the merchant portal to lift it. Current allowances are on the pricing section.

Machine-readable surfaces

Every page on this origin also serves Markdown. Request it with Accept: text/markdown, or append .md to the path — for example /developers.md.

Testing an integration

The x402 Echo Merchant is a live merchant that returns HTTP 402, for testing a client end to end against real payment terms. Quickstarts for Express, Hono, Next.js, FastAPI, Flask, and Gin are in the documentation; client quickstarts for Axios, Fetch, httpx, requests, and Go are at https://docs.payai.network//x402/clients/introduction.

Questions, support, and security reports: info@payai.network.