Rails and dialects are different dimensions
A dialect is the HTTP encoding. A rail is the on-chain settlement and authority engine selected by the offer.
| Dimension | Choice | Meaning |
|---|---|---|
| Dialect | MPP | Challenge and proof in HTTP authentication headers |
| Dialect | x402 | Offers in the PAYMENT-REQUIRED header and the 402 JSON body (gateway); JSON body only (@cmdoss/suipay-sdk/seller); payment in PAYMENT-SIGNATURE |
| Rail | delegate | Owner-funded spend account: one account, policies, scoped grants |
| Rail | direct | Non-escrow baseline; payer spends their own coin |
| Rail | recurring | Recurring mandate rail (intent: subscription) |
| Rail | allowance / auth_capture | Removed from the HTTP wire and current schema (ADR-0026) |
One 402, one settlement
A dual-dialect challenge shares one economic offer. Sui Agent Payments derives
paymentIdHash from the challenge ID and termsHash from the offer digest,
then matches them against finalized Sui events. One canonical authorization
can settle at most once (atomic compare-and-set on the settlement right, plus
on-chain replay markers for guarded rails).
Live rails vs retired allowance
Live rails the gateway will newly register and settle:
delegate(backed by a spend account)directrecurring
allowance and auth_capture are fully removed from the HTTP wire and
the current schema (docs/decisions/ADR-0026-remove-v1-allowance-auth-capture-wire-db.md).
They do not decode, they have no leftover-row 410, and they are not members
of the rail CHECK constraints. Registration treats those strings as an invalid
rail. On-chain allowance.move retirement remains deferred
(docs/decisions/ADR-0010-remove-v1-allowance-rail.md step 5). Do not document
or build new agent flows on V1 allowance. Migrate to a spend account with
MCP OAuth or a BYO delegated key.
Capability ceilings
Rail capabilities constrain dialects:
| Rail | Typical dialect mode |
|---|---|
delegate | MPP self-settled only (x402 gated off by default) |
direct | MPP and x402 gateway-settled |
recurring | MPP and x402 gateway-settled |
Always use the dialects a resource actually advertises in its 402 and catalog entry.
Try x402 in the console playground
When the console is built with NEXT_PUBLIC_PLAYGROUND_X402=true, a service
on the delegate rail whose catalog entry advertises x402 shows an
MPP / x402 switch on its /services/[slug] page. x402 mode pays from the
spend account with the same delegate key the MPP mode stores in the browser.
No wallet is prompted. The key signs a spend-account transaction that uses the
sponsor gas the gateway pinned in the offer, and the credential goes out as
PAYMENT-SIGNATURE.
The page refuses, before anything is signed, and shows why:
- a 402 with no x402 offer
- an offer on a rail other than
delegate - an offer with no pinned sponsor gas (the gateway leased none for it)
The run is shown step by step: the unpaid request and its 402 (the challenge
read from PAYMENT-REQUIRED, or from the body when that header is absent or
does not decode), the accept chosen, the transaction built, the delegate-key
signature, PAYMENT-SIGNATURE sent, PAYMENT-RESPONSE received, and the delivered
resource. Steps inside the gateway (verify, dry-run, broadcast) arrive as one
answer and are not broken out.