Docs detail
Payment Methods
Card vs crypto payment branches, wallet readiness checks, and payment failure handling.
Owner: genesis-payments
Pizza x402 supports two payment branches at confirm time:
- Card payments (
EUR, Stripe-backed) - Crypto payments (
USDCon Base via x402)
The live Go deploy is merchant-configurable, so storefronts should read:
paymentRailsfrom merchant bootstrapavailablePaymentMethodsfrom the quote
Card checkout should only render when the merchant’s configured card rail is actually available.
Canonical references:
Payment branch behavior
Card branch
- Create a quote with
POST /v1/orders/quote. - Confirm with
POST /v1/orders/confirmandpaymentMethod: "card". - Confirm response is
200withpaymentIntentIdandclientSecret. - Complete payment on frontend using Stripe Elements/Checkout.
- Order is created by webhook after successful payment.
Crypto branch
- Create a quote with
POST /v1/orders/quote. - First
POST /v1/orders/confirmwithpaymentMethod: "crypto"returns402 PAYMENT_REQUIRED. - Execute the x402 payment using
paymentRequirements(dev mock:paymentRequestIdis still accepted as the proof). - Retry
POST /v1/orders/confirmwith either the legacyPAYMENT-SIGNATUREheader or the JSONpaymentSignaturefield. - Response
200returnsorderIdand paid status.
Wallet readiness checklist
Before choosing crypto payment, confirm all of the following:
- Customer has a wallet that supports Base.
- Wallet holds enough
USDCon Base (not Ethereum mainnet). - Customer can sign/submit the payment proof before quote expiry.
- Network is
eip155:8453and asset is Base USDC.
If readiness is missing, use wallet setup guidance before retrying payment.
Wallet setup guidance
Use the canonical API endpoint:
curl -sS http://localhost:3000/v1/wallet-setup
The response includes:
- Step-by-step setup instructions.
- Recommended wallet options (Coinbase Wallet for beginners).
- Base network details (
chainId, USDC asset address, explorer, RPC). - Canonical resources (
base docs, wallet download, bridge links).
For docs consistency, prefer the endpoint response over ad-hoc setup text:
GET /v1/wallet-setup(runtime contract)AGENTS.mdand the public wallet setup guide (agent guidance)
Common payment failures and operator actions
| Error code | When it appears | Action |
|---|---|---|
PAYMENT_REQUIRED | Crypto first confirm call or payment not yet seen | Complete payment from paymentRequirements, then retry confirm with a proof payload |
PAYMENT_INVALID | Signature/proof invalid or expired | Inspect details.reason and use the cause-specific branch below |
QUOTE_NOT_FOUND | Quote expired or unknown | Recreate quote and restart confirm flow |
ASSERTION_FAILED_METHOD | Confirm method differs from expected | Reconfirm method with user and retry |
ASSERTION_FAILED_CURRENCY | Currency expectation mismatch | Validate card (EUR) vs crypto (USDC) path |
ASSERTION_FAILED_EXPIRY | Expected expiry differs or quote stale | Refresh quote and retry with updated assertions |
For PAYMENT_INVALID, the current recovery rules are:
invalid_signature: rebuild the proof payload instead of replaying the same invalid proof.expired: create a fresh quote before retrying.wrong_network: switch the wallet back to Base (eip155:8453).insufficient_funds: top up the wallet;details.requiredAtomiccarries the exact minimum needed.
Minimal confirm-time safety pattern
Use assertions on confirm calls to lock expected quote state:
expectedQuoteHashexpectedTotalCents/maxTotalCentsexpectedCurrencyexpectedPaymentMethodexpectedExpiresAtexpectedMerchantId/expectedMerchantAddress
This reduces silent divergence in agentic and scripted flows.