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
| Method | Route | Purpose |
|---|---|---|
GET | /healthz | Gateway health. |
POST | /merchant/challenge | Create a short-lived payTo ownership challenge. |
POST | /merchant/register | Register after signature verification. |
GET | /merchant/me | Read the authenticated profile. |
POST | /merchant/rotate-key | Rotate API or notify credential. |
POST | /merchant/revoke-key | Revoke the previous credential. |
POST | /ref | Create a payment reference. |
GET | /ref/:refId | Read public ref metadata. |
GET | /ref?pay_to=... | List authenticated refs with bounded pagination. |
POST | /ref/:refId/revoke | Revoke one ref. |
POST | /payto/:payTo/revoke | Retire a payTo address. |
GET | /pay/:refId | Serve the wallet signing relay page. |
GET | /receive/:payTo | Negotiate or submit an x402 payment. |
POST | /verify-receipt | Verify receipt context and chain state. |
POST | /verify-refund-receipt | Verify refund receipt and reverse transfer. |
GET | /tx/:txHash | Read bounded transaction status. |
GET | /txs | Query bounded transfer history. |
POST | /recover-settlement | Recover a post-settlement result without settling again. |
Authentication matrix
| Route group | Authentication |
|---|---|
| Health, challenge, registration, public ref lookup | Public with route-specific rate limits |
| Ref create/list/revoke, payTo revoke, merchant profile and key operations | Authorization: Bearer <apiKey> in production |
| Receive negotiation and settlement | x402 PAYMENT-SIGNATURE; no merchant API key from payer |
| Tx, history, receipt and recovery routes | Deployment policy and public-abuse gates |
| Order and refund mutation | Merchant 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
| Query | Required | Meaning |
|---|---|---|
pay_to | Yes | Tenant-owned receiver address |
limit | No | Bounded page size |
cursor | No | Opaque 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
| Query | Meaning |
|---|---|
pay_to | Incoming transfer recipient |
from | Outgoing transfer sender |
asset | Currently USDC |
from_block | Non-negative starting block |
limit | Bounded result count |
cursor | Opaque 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
| Method | Route | Purpose |
|---|---|---|
POST | /order | Create tenant-scoped unpaid order and ref |
GET | /order/:orderId | Read one order |
GET | /order | List orders by optional status |
POST | /order/:orderId/cancel | Cancel an unpaid order |
POST | /order/:orderId/refund | Create random bound refund intent |
GET | /order/:orderId/refund/:refundId | Read refund state |
GET | /order/:orderId/refunds | List order refunds |
POST | /order/:orderId/refund/:refundId/reject | Sign a rejected refund receipt |
POST | /refund-receipt/rejected | Sign 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.