Multi-Chain Settlement
cross402 decouples where a payer sends USDC from where the merchant receives it. This page explains that model from the caller's perspective: what the two chain fields mean, how the x402 protocol handles both legs, and what the caller observes as status transitions.
Two chains per intent
Every CreateIntent request carries:
payer_chain— required. The chain on which the payer holds USDC and signs an X402 authorization.target_chain— optional, defaults to"base". The chain on which the merchant receives USDC.
The merchant address is validated against target_chain. If target_chain is an EVM chain, recipient must be a 20-byte hex address; if it is solana, recipient must be a Solana public key. For email recipients, cross402 resolves the email to a wallet on the target chain via Privy — so the same email returns a Solana address when target_chain is solana, and an EVM address when target_chain is an EVM chain.
Any chain exposed by GET /api/chains may be used as either payer_chain or target_chain, including same-chain combinations (base → base, polygon → polygon, etc.). That set is currently Base, Ethereum, HyperEVM, Polygon, Solana; Arbitrum, BSC, Monad, SKALE Base, and MegaETH are 🚧 coming soon — see Supported Chains for per-chain status.
How settlement works
Both sides of an intent — payer-side collection and target-side merchant payout — run through the x402 protocol. Each side produces a signed x402 payload that cross402 forwards to the shared x402 facilitator, which executes the payment on-chain.
- Payer side — the payer's client signs an x402 payload authorizing USDC to move from the payer's wallet to cross402.
- Target side — once the source leg settles, cross402's proxy wallet signs its own x402 payload authorizing USDC to move from that proxy wallet to the merchant address on
target_chain.
The facilitator is the same component on both sides; the only thing that changes per chain is the signing flavor, which depends on what the chain's USDC contract supports:
Signing flavors
- EIP-3009
TransferWithAuthorization— used on Circle-native USDC chains (Base, Ethereum, Polygon, Arbitrum). A single signed authorization is sufficient; the facilitator relays it on-chain. - Permit2 + optional EIP-2612 — used on chains with non-standard USDC (BSC, Monad, MegaETH). The payload combines a Permit2
PermitWitnessTransferFromsignature with, when needed, a gasless EIP-2612Permitthat grants Permit2 the USDC allowance. cross402 sponsors the on-chain submission. - Solana VersionedTransaction (v0) — used when the chain is Solana. The payer or proxy wallet partially signs a VersionedTransaction carrying an SPL
TransferCheckedinstruction; the facilitator co-signs as fee payer before submission.
Callers do not select the flavor. The SDK (or a compliant x402 client) produces the correct payload from the payment_requirements block returned on CreateIntent. From the caller's viewpoint the contract is unchanged: POST createIntent, submit the signed payload, poll status.
Arbitrum, BSC, Monad, SKALE Base, and MegaETH are 🚧 coming soon; their signing-flavor rows are documented here for integration preparation.
What the caller observes
The status progression is the same regardless of which chains are paired:
AWAITING_PAYMENT
│ (payer submits X402 authorization)
▼
PENDING
│ (verification + source-chain settlement)
▼
SOURCE_SETTLED
│ (cross402 dispatches target-chain transfer)
▼
TARGET_SETTLING
│ (target-chain tx confirms)
▼
TARGET_SETTLED ← terminal
On a GetIntent response for TARGET_SETTLED, the target_payment block holds the tx hash and explorer URL for the transfer on target_chain. The source_payment block holds the corresponding source-chain tx.
Rollback
If cross402 moves the intent to TARGET_SETTLING but the target transfer cannot be dispatched — for example because the agent's target-chain wallet hasn't been provisioned for that chain — the status is rolled back atomically to SOURCE_SETTLED. Callers that poll will see this as a transient dip; the pipeline retries automatically.
Two failures are terminal:
VERIFICATION_FAILED— source-side authorization could not be verified. No funds moved on the payer side.PARTIAL_SETTLEMENT— source settled but target transfer could not be completed at all. Payer funds have moved; contact support for reconciliation.
See Statuses for the full transition table.
Fees
Fees are computed per (payer_chain, target_chain) pair and returned in fee_breakdown on every intent response:
source_chain_fee— gas/network cost on the payer side.target_chain_fee— gas/network cost on the target side (for example Ethereum gas is meaningfully higher than Base or Polygon).platform_feeandplatform_fee_percentage— cross402's service fee.total_fee— sum.
See Fee Breakdown for the exact shape.
Related
- Supported Chains — payer × target matrix and per-chain caveats.
- Statuses — full state machine.
- Architecture — end-to-end flow.