Skip to content

HTTP API

Reference the core merchant, PaymentRef, receive, receipt, transaction, and recovery routes.

All JSON routes use application/json. Merchant APIs authenticate with a bearer API key. x402 payment submission uses PAYMENT-SIGNATURE.

Core routes

MethodRoutePurpose
GET/healthzGateway health.
POST/merchant/challengeCreate a short-lived payTo ownership challenge.
POST/merchant/registerRegister after signature verification.
GET/merchant/meRead the authenticated profile.
POST/merchant/rotate-keyRotate API or notify credential.
POST/merchant/revoke-keyRevoke the previous credential.
POST/refCreate a payment reference.
GET/ref/:refIdRead public ref metadata.
GET/ref?pay_to=...List authenticated refs with bounded pagination.
POST/ref/:refId/revokeRevoke one ref.
POST/payto/:payTo/revokeRetire a payTo address.
GET/pay/:refIdServe the wallet signing relay page.
GET/receive/:payToNegotiate or submit an x402 payment.
POST/verify-receiptVerify receipt context and chain state.
POST/verify-refund-receiptVerify refund receipt and reverse transfer.
GET/tx/:txHashRead bounded transaction status.
GET/txsQuery bounded transfer history.
POST/recover-settlementRecover a post-settlement result without settling again.

Authentication matrix

Route groupAuthentication
Health, challenge, registration, public ref lookupPublic with route-specific rate limits
Ref create/list/revoke, payTo revoke, merchant profile and key operationsAuthorization: Bearer <apiKey> in production
Receive negotiation and settlementx402 PAYMENT-SIGNATURE; no merchant API key from payer
Tx, history, receipt and recovery routesDeployment policy and public-abuse gates
Order and refund mutationMerchant bearer key and enabled order mode

Merchant registration

POST /merchant/challenge

JSON
{ "payTo": "0x1111111111111111111111111111111111111111", "network": "base", "action": "merchant.register", "webhookUrl": "https://merchant.example/x402/notify"}

The response contains challengeId, the canonical challenge message, and signingMessage. Challenges bind gateway origin, action, payTo, network, optional webhook hash, nonce, issue time, and expiry.

POST /merchant/register

JSON
{ "challengeId": "challenge_...", "payTo": "0x1111111111111111111111111111111111111111", "network": "base", "label": "Example Store", "webhookUrl": "https://merchant.example/x402/notify", "signature": "0x..."}

The one-time response includes merchantId, apiKey, notifyHmacKey, notifyHmacKeyId, and payTo.

PaymentRef routes

POST /ref

JSON
{ "payTo": "0x1111111111111111111111111111111111111111", "network": "base", "asset": "USDC", "amount": "24000000", "invoiceId": "order_7K9M2", "label": "Order 7K9M2", "description": "Example Store checkout", "expiresInSecs": 900, "notifyUrl": "https://merchant.example/x402/notify"}

The response contains refId, transport-safe refUrl, and the immutable payment snapshot. Omit amount for an open ref. invoiceId requires a fixed amount.

GET /ref

QueryRequiredMeaning
pay_toYesTenant-owned receiver address
limitNoBounded page size
cursorNoOpaque cursor from the previous response

The response is { "items": [...], "nextCursor": "..." }. Do not construct or modify cursors.

Receive negotiation

Without PAYMENT-SIGNATURE, /receive/:payTo returns 402 with a base64url-encoded payment-required header. With a valid payment signature it verifies the exact context, calls facilitator /verify and /settle, and returns a settlement response containing the tx hash.

Common ref query fields are ref=<refId> and, for open refs, amount=<atomic>. Refund flows also bind refundOf=sha256:<receiptHash>.

Negotiation response

PaymentRequired binds resource URL, exact scheme, network, atomic amount, token contract, payTo, timeout, and extensions. Production responses should include a signed offer whose gatewayOrigin, resourceUrl, paymentId, payTo, amount, network, chain id, asset, expiry, and nonce match the request.

Settlement request

The PAYMENT-SIGNATURE header contains the base64url x402 payload. It includes the accepted requirement, EIP-3009 signature and authorization, plus payment-identifier. Treat the header as replayable sensitive material and never log it.

Settlement response

JSON
{ "x402Version": 2, "success": true, "network": "base", "transaction": "0x...", "payer": "0x...", "receiptStatus": "issued", "response": { "code": "settled", "message": "payment settled" }, "extensions": { "offer-receipt": { "signedReceipt": "...", "receipt": { "type": "x402.payment.receipt", "txHash": "0x..." } } }}

Verification and history

POST /verify-receipt

Send signedReceipt, the complete receipt, optional expectedPayTo, optional expectedAmount, and minConfirmations. The result separates signature/context validity from confirmation policy and includes field match evidence.

GET /tx/:txHash

Returns found, status, confirmations, block number, transfer endpoints, token contract, value, and bounded logs where available.

GET /txs

QueryMeaning
pay_toIncoming transfer recipient
fromOutgoing transfer sender
assetCurrently USDC
from_blockNon-negative starting block
limitBounded result count
cursorOpaque continuation token

At least pay_to, from, or cursor is required. Deployments enforce maximum block span, response bytes, RPC timeout, and request rate.

POST /recover-settlement

Send refId, original paymentPayload, and optional tx hash, signed offer, or starting block. Recovery checks immutable ref context and chain evidence. It must not call facilitator settle again.

Optional order and refund routes

MethodRoutePurpose
POST/orderCreate tenant-scoped unpaid order and ref
GET/order/:orderIdRead one order
GET/orderList orders by optional status
POST/order/:orderId/cancelCancel an unpaid order
POST/order/:orderId/refundCreate random bound refund intent
GET/order/:orderId/refund/:refundIdRead refund state
GET/order/:orderId/refundsList order refunds
POST/order/:orderId/refund/:refundId/rejectSign a rejected refund receipt
POST/refund-receipt/rejectedSign a stateless rejected refund receipt

Every order lookup is scoped by authenticated merchant id. Bare orderId is never a global authority.

Error envelope

JSON
{ "x402Version": 2, "error": { "code": "ref_expired", "message": "payment reference expired", "details": {} }}

Stable codes include invalid_request, unauthorized, forbidden, not_found, ref_expired, ref_revoked, payto_revoked, payment_required, payment_verification_failed, settlement_failed, receipt_invalid, rpc_unavailable, and rate_limited.

Errors use stable structured codes so SDKs can distinguish invalid input, refusal, temporary unavailability, and ambiguous post-settlement recovery states.