Merchant API
Reference for x402-paysdk/merchant authentication, refs, orders, refunds, receipts, notify, tx history, and reconciliation.
TypeScriptimport { MerchantClient } from 'x402-paysdk/merchant';
This entry point is backend-only. It handles bearer credentials, notify HMAC keys, merchant-controlled wallet signers, and business evidence.
MerchantClient
TypeScriptconst client = new MerchantClient({ gateway: 'https://pay.example.com', apiKey: process.env.X402_API_KEY!, notifyHmacKey: process.env.X402_NOTIFY_KEY, notifyHmacKeyId: process.env.X402_NOTIFY_KEY_ID, notifyNonceStore, merchantWalletSigner, payTo, network: 'base'});
| Option | Purpose |
|---|---|
gateway | Canonical gateway origin |
apiKey | Required bearer key for authenticated requests |
notifyHmacKey, notifyHmacKeyId | Optional current notify credential |
notifyNonceStore | Atomic replay store used by high-level notify verification |
merchantWalletSigner | Optional merchant-controlled signer for reverse x402 refunds |
payTo, network | Optional defaults for merchant operations and refunds |
client.request<T>(path, init?) sends an authenticated same-origin request. Paths must begin with one / and cannot escape the configured origin.
Merchant registration and keys
| Function | Purpose |
|---|---|
createMerchantChallenge(gateway, request) | Request payTo ownership challenge |
merchantChallengeSigningMessage(message) | Build canonical EIP-191 challenge text |
merchantChallengeTypedData(message) | Build EVM EIP-712 ownership typed data |
registerMerchant(gateway, request) | Submit signature and receive one-time credentials |
getMerchantProfile(client) | Read authenticated profile |
rotateMerchantKey(client, { keyType }) | Rotate apiKey or notifyHmacKey with overlap expiry |
revokeOldMerchantKey(client, options) | Revoke the old tenant-scoped key |
Registration returns merchantId, apiKey, notifyHmacKey, notifyHmacKeyId, and payTo. Store raw keys immediately; do not expect to read them again.
Reference management
| Function | Purpose |
|---|---|
createPaymentRef(client, options) | Create an authenticated fixed or open ref |
getRef(client, refId) | Read public snapshot |
listRefs(client, options) | List tenant refs by payTo with bounded pagination |
revokePaymentRef(client, options) | Revoke a ref with optional bounded reason |
revokePayTo(client, options) | Retire a payTo address |
Merchant create options match the receiver API but omit gateway and apiKey, which come from the client.
Optional order mode
| Function | Signature summary |
|---|---|
createOrder | (client, { payTo, amount, asset?, network?, orderId?, description?, metadata?, expirySecs? }) |
getOrder | (client, orderId) |
listOrders | (client, { status?, limit?, cursor? }?) |
cancelOrder | (client, orderId) |
createOrderRefund | (client, { orderId, amount, refundId?, originalPaymentRef, expiresInSecs? }) |
getRefundStatus | (client, orderId, refundId) |
listRefunds | (client, orderId) |
Order status is unpaid | pending | paid | confirmed | failed | cancelled | partially_refunded | fully_refunded. Routes may be unavailable when gateway order mode is disabled.
Refunds
refund(client, options) performs a reverse x402 payment with the merchant wallet. Order mode creates a bound refund intent first; stateless mode requires originalPayer, refundId, network, original receipt hash, original amount, cumulative refunded amount, sequence, and FULL | PARTIAL result.
Use rejectRefund(client, options) for a signed REJECTED refund receipt. It does not move funds or call the facilitator.
Receipt and tx verification
| Function | Purpose |
|---|---|
verifyReceipt(client, options) | Verify signed payment receipt and chain transfer |
verifyRefundReceipt(client, options) | Verify signed refund receipt and reverse transfer |
verifySignedPaymentReceipt(options) | Local signature and expected-field verification |
verifySignedRefundReceipt(options) | Local refund signature and expected-field verification |
paymentReceiptContentHash(receipt) | Canonical payment receipt reference |
refundReceiptContentHash(receipt) | Canonical refund receipt reference |
getTxStatus(gateway, txHash) | Bounded transaction status |
getPaymentHistory(gateway, options) | Bounded Transfer log history |
Local signature verification establishes gateway attestation. Network verification establishes chain finality.
Notify verification
| Function | Replay-safe? | Use |
|---|---|---|
verifySettlementNotify(headers, rawBody, keys, nonceStore, ...) | Yes | Verify HMAC, headers, body binding, event schema, timestamp, and nonce |
verifyNotifySignature(headers, rawBody, keys, nonceStore, ...) | Yes | Verify envelope without parsing event body |
notifyMiddleware(options) | Yes | Express-compatible middleware using raw body access |
createMemoryNotifyNonceStore() | One process only | Tests and local development |
verifyNotifySignatureWithoutReplayProtection(...) | No | Diagnostics only; never guard side effects |
Production multi-instance systems need a shared atomic NotifyNonceStore.putIfAbsent(key, expiresAt) implementation.
Reconciliation
TypeScriptconst report = await reconcile(client, { payTo, fromBlock, limit: 200, receipts, refundReceipts, trustedSigners, minConfirmations: 3, verifyChain: true});
The result contains incoming and outgoing transfer evidence, anomalies, the last observed block, and optional cursors. Reconciliation reports mismatches; it never mutates merchant orders automatically.
Anomalies include transfers without receipts, receipts without transfers, signature/chain verification failures, duplicates, refund evidence mismatches, cumulative mismatches, and refunds exceeding the original amount.