Skip to main content
Stripe checkout is Trails’ merchant settlement path: you state a price in USD, the shopper pays with any token they hold on any supported EVM chain, and you settle in USD on your Stripe account with a Stripe-hosted receipt. Requires 0xtrails@0.19.0 or later. Access is arranged through Polygon Checkout; the stripe prop fails at quote time until a Stripe merchant key is mapped to your Trails project.

Quick start

That is the whole integration. The stripe prop forces pay mode and derives the destination server-side, so the destination props (toAddress, toAmount, toChainId, toToken, toCalldata, actions, and the advanced settlement prop) must be left unset. Passing any of them alongside stripe throws at render.
Use TrailsWidget from 0xtrails for Stripe checkout. The focused <Pay /> component requires a to destination, which conflicts with the server-derived one, and does not expose onPaymentCreated.

How it works

All Stripe knowledge lives in the Trails API. The SDK forwards a settlement request through the normal quote flow, and the API creates and arms a Stripe PaymentIntent, allocates the USDC deposit address, and derives the destination from it. Trails routes the shopper’s token into that deposit, and the settle step is tracked on the intent receipt until Stripe attributes the deposit. No Stripe key ever reaches the browser, and no merchant backend is required to take a payment. The wire types shipped earlier in @0xtrails/api@0.18.5. Origins must be EVM chains; settlement quotes are not supported from non-EVM (edge) origins.

The stripe prop

Changing amountCents while orderRef stays the same keeps the checkout reference: the API cancels the armed payment and re-arms it at the new amount. When orderRef is omitted, one checkout reference spans the lifetime of the stripe prop, so set the prop to undefined between purchases on a long-lived mount. Use getStripeSettlementChainIds(mode) to validate a chain taken from untrusted input before passing it as chainId:

Callbacks

QuoteSettlementInfo has provider, reference (the Stripe PaymentIntent id), currency, amountCents, amountUsd, livemode and chainId. IntentSettlement adds the live state: status (raw Stripe status), settled, failed, terminal, and externalUrl (the Stripe-hosted receipt once available). Key terminality on terminal, never on the status string. terminal can be true with both settled and failed false when the payment was retired with an unknown outcome, so gate fulfillment on settled alone.

Flow

  1. The widget quotes with a settlement descriptor instead of a destination. The API creates and arms a Stripe PaymentIntent for the checkout reference and returns the derived destination. onPaymentCreated fires.
  2. The shopper picks any token on any chain and confirms once. Trails swaps, bridges and deposits USDC to the Stripe-allocated address.
  3. The intent reaches its terminal on-chain status. The pending screen shows a single processing state instead of per-hop steps.
  4. Stripe attributes the deposit, usually within one to two minutes. The receipt’s settlement.settled flips, the receipt screen shows the Stripe receipt link, and onSuccess fires.
Settlement quotes never take the passthrough (direct transfer) path, so every settled payment has an intent id your backend can verify.

Bounded waits

Settlement tracking fails open rather than holding checkout forever. If the payment stays pending past the hold window, onSuccess fires with the pending settlement attached (settled: false) and polling continues slowly in the background. A failed payment releases the same way with settlement.failed set. The windows are exported as constants (INTENT_SETTLEMENT_POLL_MS, INTENT_SETTLEMENT_PENDING_HOLD_MS) if you need to mirror them.

Verify before you fulfill

amountCents and orderRef are declared by the browser under a public access key. A settled payment proves the declared amount was deposited, not that it matches your order. Your fulfillment backend must independently check the settled amount, order reference and chain against your own records before shipping.
Read the intent receipt with the GetIntentReceipt endpoint and compare settlement to the order:
This is the canonical verification example; the API reference and use-case pages link back here.

Tracking settlement outside the widget

An order confirmation page that outlives the widget can poll the receipt itself with useIntentSettlement. See Settlement in the hooks reference for the hook, its state shape and a full example.

Presentation

The stripe prop implies merchantCheckout, which renders the widget as a payment step rather than a standalone transfer tool: one processing state while pending, and a receipt that keeps only the payment receipt links (no explorer link, completion time or “Start new transaction”). Set merchantCheckout={false} to keep the standalone presentation, or set it to true on any other integration to borrow the checkout look. The recipient selector is read-only for settlement checkouts, since the deposit address belongs to Stripe.

Headless

Everything the widget does is available to headless integrations:
  • useQuote accepts a settlement option (QuoteSettlementParams: provider: 'stripe', amountCents, checkoutRef, orderRef?, chainId?) and the quote result carries settlement. The hook still needs a to with chain, token and recipient before it quotes; pass the settlement chain and its USDC address as placeholders (the widget uses the USDC contract address as the recipient). The SDK strips them from the request and the API derives the real destination from the armed payment. Do not pass to.calls, to.calldata, actions or from.amount: settlement quotes are exact-output and the hook throws on those.
  • The advanced settlement widget prop takes the same params directly when you manage the checkout reference lifecycle yourself.
  • useIntentSettlement and getTrailsClient cover receipt polling.
The API surface is documented under QuoteIntent and GetIntentReceipt.

Test mode

With a Stripe test-mode merchant key, deposits settle on Base Sepolia only and stripe.testMode must be set. Requesting any other chainId under a test key is rejected before a payment is created. Treat test-mode checkouts as an integration check, not a pricing check.

Compared with the Stripe onramp

The onramp is the reverse direction: a card funds crypto into an intent. The two can be combined, so a checkout with the stripe prop can still offer the Stripe onramp tile as one way for the shopper to fund the payment. See the Stripe overview for a side-by-side comparison.