x402 and MPP charge
The token a payment carries, and the two rails that settle it
A rail is how a buyer's USDC reaches SplitRouter on Base. There are two: x402 and MPP charge.
A purchase pays out identically on either: same arithmetic, same escrow record, same commission and
cashback.
The attribution token
Attribution rides on a token, and both rails carry the same one.
A ref link is the URL a published review is issued, and everything that matters about it is inside the URL. Its path segment is one base64url blob: a JSON payload with a 64-byte Ed25519 signature over that payload appended, then the two encoded together — not a signature appended to an already-encoded payload. Decode the segment and the trailing 64 bytes are the signature; the rest is the token.
Publication mints it on both publish paths, immediately after the on-chain review exists, and stores it on the review — so a published review always has one, and a review whose content never reached us has none and cannot be bought through. See Reviews.
| In the payload | What it is |
|---|---|
| Who and what | the reviewer's agent id, review id, merchant id and product id. This is the whole of attribution: a settled purchase traces to one review and one reviewer, and to nothing else |
| The pay target | the split contract's address and its chain id, plus the merchant's own referral endpoint |
| The frozen cashback ratio | the reviewer's pledged share of its own commission, in basis points of the commission and capped — fixed when the review enters our records. See Commission & cashback |
| The product type | repeat or one_off, which selects which of the reviewer's two Review Ranks applies. See Ranks |
| An issue timestamp | and a setup pointer: a URL an agent that cannot complete the payment can follow to onboard itself |
| The commission rate | informational, for display and tracing. The rate that applies is the live one in the table below |
Self-contained, so a buyer can pay at the edge. The pay target means an agent holding a token knows where to buy and where the money goes without asking us. Resolving the link — requesting its own URL — verifies the signature, decodes the payload and returns its fields, and records a best-effort attribution event that nothing in ranking, ordering or payout reads. The path to prefer needs no round-trip at all: fetch our attribution public key once from the well-known manifest, verify the token locally, and go straight to the merchant endpoint it names.
Permanent and reusable. No expiry in the payload and no revocation list, because everything worth bounding is read live at settlement instead: the rate, the merchant's and the product's active state, and the commission multiplier — which is not in the token at all. It is derived from the reviewer's current Review Rank when the split runs, so an old link cannot lock in a multiplier its reviewer has since stopped deserving.
What both rails share
| Target | SplitRouter on Base, in USDC |
| Arithmetic | one shared library computes all five legs — see Payment flow |
| Commission rate | read live on-chain from ProductRegistry at settlement. Never from the token, never from the caller, so the merchant's current rate applies |
| Preconditions | merchant active and product active when the split runs |
| Attribution | the token above names the review, reviewer, merchant and product. No valid token, no commission |
| Escrow | one record per purchase, holding the held-back commission and the buyer's cashback — see Payment flow |
x402
The HTTP payment protocol. Six steps, all inside one request-retry cycle:
- The buyer calls the merchant's referral endpoint with the token in an
X-Referrer-Tokenheader and its own agent id inX-Referrer-Buyer-Agent-Id. The presence of the first header is the signal, not its value. - The merchant answers
402, naming the split contract as the payment target and our facilitator as the facilitator URL, and echoing the attribution fields back. That echo is what makes the response self-describing: an agent with no prior knowledge of this protocol can read it and comply — provided it signs the authorisation itself. See the caveat below step 5. - The buyer signs an ERC-3009
ReceiveWithAuthorizationletting the split contract pull the amount, and retries with the signed payment. The typehash is not the x402 default: the split contract callsreceiveWithAuthorization, soTransferWithAuthorization— same fields, different struct name — hashes differently and USDC rejects it. The402'sextra.authorizationTypeand the ref link'sauthorizationTypeboth name the required type. - The merchant passes that payload to our facilitator, server to server.
- The facilitator verifies the token's signature and chain, resolves the reviewer's current Review
Rank into the commission multiplier, and calls
route().
What "self-describing" does and does not buy you. Everything an agent needs arrives in-band —
the ref link and the 402 both name the contracts, the amount and the authorisation type. But a
stock x402 SDK client cannot pay this rail: the exact/EVM scheme pins its EIP-712 type table
inline, with no configuration path, so it will always sign TransferWithAuthorization. An agent
that builds and signs the authorisation from these instructions is unaffected, which is what the
native-integration guide covers. The consequence is that settlement is not permissionless: no
third-party facilitator can push a payment through. That is a liveness dependency on our
facilitator, not a safety one — nothing moves and no buyer funds are at risk while it is down.
6. route() pulls and splits in one transaction, then the merchant serves the resource. The
escrow record stores the keccak256 of the signed token, binding that escrow to the exact
token presented.
route() accepts calls only from FACILITATOR_ROLE, which today means us. It is atomic: if
anything reverts, including after the pull, the whole transaction unwinds and the buyer's balance
is untouched.
A buyer with no agent identity can pay here. It omits its buyer agent id, the facilitator substitutes the sentinel that marks an agent-less purchase, and the reviewer's commission settles as normal while the cashback waits in escrow for a wallet to bind an identity to it.
MPP charge
Here the payment arrives first and is attributed second.
- The buyer sends its USDC charge straight to the split contract. It is pooled there.
- The buyer submits the charge to us: transaction hash, attribution token, buyer agent id, and a
ChargeCommitmentsignature proving the wallet that paid is the wallet claiming the attribution. See Identity and commitments. - We verify before signing anything — the transfer must be visible on-chain at a configured confirmation depth, and its payer and amount are read from the chain.
- The
ORACLEkey signs aChargeAttestationnaming the review, the buyer agent, the commission multiplier and the cashback rate. splitCharge()splits. Anyone may submit it.
Four checks gate step 4. The token must verify and name this chain; on this rail it must also be recent, and a token older than a configured window on the order of minutes is rejected. The buyer agent id must be owned by the paying wallet. The merchant and product must be active — attestation time is the only moment that check can prevent anything, because by then the buyer has paid and the merchant has served the resource.
There is no agent-less path here: the submission requires a buyer agent id, owned by the paying wallet.
When there is no valid token
A payment reaching our facilitator without one is refused, at verification and at settlement alike — as is a token whose signature does not verify, and one minted for a different chain than the one it is spent on. The rejection carries the setup pointer, so an agent that arrived without a token learns how to get one.
Nothing credits a reviewer afterwards: no cookie, no session, no reconciliation window, no support request. Attribution travelled with the payment or it did not exist — the same property that makes a reviewer's claim on a commission checkable.
Verification and settlement both reject a self-referral — a purchase where the buyer agent and the reviewer agent resolve to the same owner wallet — because it would rebate the buyer its own commission and inflate the reviewer's rank. This is hygiene against the zero-effort case, not a boundary: it fails open by design, so a second wallet passes, as does an agent-less buyer with no identity to compare, or an owner lookup that errors.
How they differ
| x402 | MPP charge | |
|---|---|---|
| Entry point | SplitRouter.route() | SplitRouter.splitCharge() |
| Who may call it | FACILITATOR_ROLE only — today, us | anyone |
| What authorises it | the caller's role, plus a token we verify off-chain | an ORACLE-signed attestation, verified on-chain |
| When the buyer pays | inside the settling transaction, by ERC-3009 pull | before settlement, as an ordinary transfer |
| If the split reverts | nothing moves | the USDC stays pooled in the router until ADMIN recovers it |
| Replay guard | the ERC-3009 authorisation nonce | the payment reference, consumed once on-chain |
| Token freshness | none; a ref link is permanent | required, within a configured window |
| Agent-less buyer | supported, via the sentinel buyer id | not supported |
Rules
- A ref link's token is an Ed25519-signed payload, base64url-encoded into the URL path. Only our attribution key can mint one; anyone with the public key can verify one.
- A token exists only for a published review, and issuing it is part of publishing. A review whose content never reached us has no link, and nothing can be bought through it.
- The token is self-contained — split contract, chain and merchant endpoint — so a buyer can pay at the edge with no resolution call. Resolving one records a best-effort event that no ranking or payout path reads.
- The cashback ratio in the token is frozen when the review enters our records and never changes — not on a content edit, and not when the reviewer changes its default rate.
- A ref link does not expire and cannot be revoked. Terms and active state are checked live at settlement instead.
- Both rails settle in USDC on Base, into the same contract, on the same arithmetic. There is no third rail. Neither is deployed on a public chain yet — not Base mainnet, not Base Sepolia — so both are exercised on a local node, and everything here describes the contracts as written. See The contracts.
route()acceptsFACILITATOR_ROLEonly.splitCharge()has no role gate — the oracle signature is the authorisation and the caller is irrelevant.- A charge's payment reference is consumed exactly once on-chain, so no charge settles twice.
- The commission rate is read live at settlement on both rails, never from the token and never from calldata: the rate the token carries is informational, and the rank-derived commission multiplier is not in the token at all. Both rails require the merchant and the product to be active.
- x402 is atomic; MPP
chargeis not. A settlement-time revert on the charge rail strands the buyer's funds in the router untilADMINcalls the recovery function. - An agent-less purchase is an x402 purchase.
- A payment with no valid token for this chain is refused at verification and at settlement, and nothing credits a reviewer after the fact.
- A purchase whose buyer and reviewer agents share an owner wallet is refused at both points — but the check fails open by design: an agent-less buyer skips it, and so does an owner lookup that errors.
- MPP
sessionchannels are not supported, and neither is a second settlement chain. Any design document describing a payment channel or a session close is stale.
In the API
The facilitator's verify and settle endpoints are a server-to-server surface a merchant's x402
middleware calls; the charge submission is a REST call; the link-resolution route is the optional
one. All three are in Merchant routes, and the buyer-side payment
tools, which handle the header, the 402 and the payload for you, are in
Signer tools. Both entry points, and the attestation the second one takes,
are in Escrow and router; the ChargeCommitment type
string is in The eight commitments. To integrate, follow the
merchant quickstart, then
Accept agent payments over x402.
Next steps
- Reviews — the publication that issues the token
- Payment flow — the split arithmetic they share
- Protocol — which key can move the funds a failed charge leaves pooled