PayAI’s facilitator support is a public preview with bounded channel capacity. The shared lane requires no PayAI account or API key. Use an API key for paid usage, account attribution, or an assigned enterprise lane. The client and server implementation is available in the official upstream
@x402/core and @x402/svm npm packages.1. Choose public or authenticated access
The public shared lane accepts facilitatorPOST /verify and POST /settle without an Authorization header. This includes deposits, claims, distributions, merchant seals, refunds, and exact-request recovery. Customers and merchants do not need a PayAI account to use that lane.
Authentication is optional. Create a key in the merchant portal when you need paid usage beyond the free allowance, dashboard attribution, or an assigned enterprise lane, then follow the authentication guide. If an Authorization header is present, PayAI validates it; an invalid, expired, or revoked credential returns 401 Unauthorized instead of silently falling back to anonymous access. An authenticated request refused by policy may return 403. These are separate from the 402 Payment Required challenge your service sends to its customer.
GET /supported is public. Read it without authentication:
x402Version: 2, scheme: "batch-settlement", and your Solana network. Its extra contains the shared-lane feePayer and batchPolicy; it does not require an API key. Preserve this fee payer for the channel’s lifetime. During an admission pause, the batch entry is removed from discovery while existing channels can still be paid out and closed using their saved terms.
Enterprise accounts should send their merchant API JWT when calling /supported to discover their assigned lane and on every later /verify and /settle request for that channel. Applications should use the returned address rather than hardcode signer indices. Anonymous requests are restricted to the shared lane; a supplied credential cannot silently downgrade there when validation fails. Batch and exact payments share each lane’s fee-payer and queue capacity.
2. Prepare your USDC receiving account
The wallet inpayTo must have its USDC associated token account (ATA) on the selected network before customers open channels. Creating it requires a one-time SOL rent deposit. The facilitator sponsors channel setup and transaction fees; it does not create the merchant’s receiving ATA during settlement.
You can create the ATA yourself and fund its rent, or use the merchant portal. Link the wallet you will use as payTo and follow the token-account setup flow. The portal may sponsor the first linked Solana wallet’s USDC ATA when eligible and within its daily allowance; manual creation currently defaults to 200 credits. Check the portal’s displayed price and eligibility. A separate voucher-signing operator does not replace the receiving wallet’s ATA.
The free settlement allowance is not a signup grant of portal credits. Check your credit balance in the portal.
3. Install the upstream SDK
SVM batch settlement is included in the official upstream@x402/core and @x402/svm packages starting with version 2.28.0. Pin both packages to the same release for a reproducible integration:
@x402/core and @x402/svm on the same version when upgrading.
Use BatchSvmScheme from @x402/svm/batch-settlement/server for the merchant, and the same-named class from @x402/svm/batch-settlement/client for the customer. For merchant-signed vouchers, configure the server’s operator signer. The terms identify voucherSigner: "server" and the operator’s public key.
The operator can authorize up to the channel’s escrow, so every customer must trust it explicitly and cap the total deposit held under it:
maxDeposit caps the channel’s total escrow, including top-ups; it is separate from PayAI’s 100 USDC admission ceiling for each initial deposit.
The merchant should self-manage its receiver-authorizer key and pass it as receiverAuthorizer in the server scheme. The SDK advertises and binds that key when the channel opens, then uses it to authorize cooperative refunds and merchant seal. Keep both the operator and receiver-authorizer keys until every associated channel drains.
4. Set channel terms and durable storage
The public preview limits are below. ReadbatchPolicy from /supported for the active values; admission can pause when capacity or sponsorship funds are unavailable.
The initial deposit limit applies when opening a new channel; it is not a lifetime channel-balance ceiling. A new top-up counts as a deposit attempt but does not consume another channel slot. Recovering an existing operation must not allocate another charge or channel. Ordinary metered requests use the merchant’s off-chain channel state, so the deposit rate limit is not an inference/request throughput limit.
The 72-hour idle timer measures time since the last facilitator touch and is independent of the withdrawal grace period. A longer grace period increases how long the customer may wait for withdrawal after close begins. Keep merchant redemption frequent: choosing a 24-hour grace does not mean waiting 24 hours to pay the merchant.
Set the client SDK’s
depositAmount explicitly within these limits; its default may be only one request’s price. PaymentRequirements.amount is the maximum authorized charge for one request, not the channel’s deposit. Reserve that ceiling before work, then settle with the measured amount in the range zero through the ceiling. Serialize merchant-signed requests within each channel. Use multiple channels for parallel work until the upstream operation store supports ordered concurrent cumulative vouchers.
Implement the exported ChannelStore and BatchOperationStore contracts with shared Redis, PostgreSQL, or equivalent atomic storage. The included memory stores are for local tests only. A custom durable BatchOperationStore must retain the original reservation and persist the completed operation’s optional response field; make those updates atomic. Without the stored response, completed-response replay is unavailable for that record. Keep the store durable, backed up, shared between replicas, and protected from eviction. Keep client channel and pending-request records durable too.
When a completed server-signed request is retried with the same stable request key, matching payment payload and unchanged charge ceiling, the SDK returns the stored x402 settlement response with extra.replayed: true and skips a second merchant-handler execution. This replay works after the original proof expires. A completed legacy record with no stored response, or a retry with a changed ceiling, returns duplicate_settlement instead of creating a new settlement.
The SDK does not store or replay the protected resource’s response body. Your application must retain that result for each stable request key and return it when the request is retried. Commit application effects and the replayable resource result atomically where possible, or make the underlying work idempotent. Payment storage alone cannot provide exactly-once application effects.
The customer’s reusable authorization is a bearer credential for the channel’s lifetime. Protect it like a secret. The operator can sign cumulative charges up to the channel’s funded balance; the signed voucher returned in the payment response provides evidence of a charge, but does not make the on-chain program enforce your application’s pricing. Use an operator key with appropriate custody and rotation procedures, and retain it until its channels are drained.
5. Claim, distribute, and verify payout
Run the exportedBatchChannelManager against the same durable store and facilitator client. The shared lane works without credentials; attach authentication when using an assigned enterprise lane or paid account usage. Configure its rpcUrl or readPayoutWatermark callback so it can reconcile the confirmed paid state before updating merchant bookkeeping. It claims saved vouchers, then distributes settled funds to the receiving ATA. Use a cadence comfortably inside the withdrawal grace period, such as 10–60 seconds, and alert on failed or delayed redemption. Preserve each channel’s original network, asset, receiver, operator, fee-payer, and access mode.
A successful claim is not merchant payment. The subsequent distribution must succeed, and the merchant ATA’s USDC balance must increase by the expected amount. Compare signed receipts, cumulative channel state, distribution transaction identities, and actual USDC receipts. Replayed operations must not be counted as new volume.
One channel per distribution request is supported. Use it when you need to attribute an on-chain USDC payout to one channel; aggregating several channels into one transaction yields a recipient-level token balance delta rather than a channel-level receipt.
A distribution request sweeps what is currently owed. An identical later request can therefore pay a newer claim; it is not an immutable payout ID. The request format does not require a payout idempotency key or payout watermarks. A recovered response returns the original transaction’s actual amount, not zero. Deduplicate accounting by network, transaction, asset and recipient instead of summing successful HTTP responses. A response for an older payout must not mark a newer claim paid.
The public preview supports at most four channels per claim transaction. Configure maxChannelsPerBatch accordingly. For shutdown, flush claim and distribution work, initiate close, wait through the grace period, and verify the remaining customer balance is refunded and channel rent is reclaimed. Continue recovery workers while new admission is paused.
For new channels, advertise a merchant receiverAuthorizer in the payment terms and retain its signing key. The facilitator binds that key at the first deposit; a key supplied only in a later close request is not trusted. Configure the same signer as BatchChannelManager.closeAuthorizer. If a claim encounters a payer-initiated Closing channel, the manager submits its latest retained voucher as a merchant-authenticated seal during withdrawal grace. You can call sealClosingChannel(channelId) directly. The facilitator applies settle_and_seal and distributes in one transaction; verify the merchant USDC receipt and payer refund from that transaction. Channels opened before the key binding was stored cannot use merchant seal; keep ordinary claims current before any close.
PayAI’s facilitator deployment routes confirmed cooperative seal payouts through onDistributionConfirmed and records cooperative-refund distributions. The facilitator persists the payout amount and callback marker across retries, and returns settlement_pending while durable accounting still needs to finish. Keep callback implementations idempotent by transaction.
A merchant outage can still lose revenue: PayAI does not retain unclaimed vouchers on the merchant’s behalf, and idle cleanup only sees the on-chain settled watermark. Keep vouchers and claim intents durable, run the claim worker frequently, and alert when it falls behind. The 72-hour idle window does not extend the withdrawal grace of a channel already closing.
Recovery and limit errors
Do not allocate another charge or build a replacement transaction merely because a response was lost. Retain the official SDK’s original payment payload and retry it unchanged; PayAI’s facilitator preserves pending transaction identity so the combined flow can reconcile the outcome after restart. A later cumulative watermark alone does not prove that a particular request succeeded. Keep recovery records and retry promptly. PayAI retains unresolved signatures and signed bytes without automatic expiry; completed results retain a 24-hour recovery window. Keep permanent receipts in your own storage. An expired blockhash plus missing transaction history does not authorize a replacement payment. Restore history or contact PayAI if the outcome remains unknown.
There is no operation-status lookup endpoint in this preview. Retrying the exact payment payload remains the transaction-reconciliation mechanism after a timeout. Reconcile payouts using the confirmed transaction signature, channel membership, cumulative watermark, and receiver USDC balance delta. A retry response alone is not a new payment.

