Skip to main content
CheckoutContainer is the plug-and-play checkout: hand it an offer and it renders whichever provider that offer belongs to. Superstate swap, Ondo buy, Ondo sell, CoinList token sale - you write one integration, not four. This is the highest rung of the SDK (L3, components) and the one to start from. Reach for a provider-specific container or the hooks below it only when you need markup the SDK does not give you.
Prefer CheckoutContainer over OndoBuyCheckoutContainer, OndoSellCheckoutContainer or SuperstateSwapCheckoutContainer even when you know the offer type. The provider containers exist, but routing on offer.type yourself means a new provider is your problem; using CheckoutContainer avoids requiring provider-specific routing when new providers are added.

Prerequisites

Render it

That is the whole integration. The container is self-scoped: it renders fully styled with no style provider in the tree.

Props

One mount, one offer, one chain

To render a different offer or chain, remount rather than reassign. Give the container a key that changes with them, as the example above does. offer and chain are read as fixed for the lifetime of the mount. Each provider’s viewmodel owns a step machine - which wallet was authorized, how much is being spent - and that progress is bound to the offer it was made against: a Superstate wallet authorization is allowlisted per offer, and an ERC-20 approval is granted per chain. Changing either prop in place would carry a completed step from one offer onto another. Worse, a swap could land mid-execution, between an approval and the broadcast it was granted for. React discards the old flow’s state along with its component instance, which is the only reset that cannot strand an in-flight transaction.

CheckoutConfig

CheckoutConfig is keyed by OfferType, and every key is required. That is not an oversight. A host that renders CheckoutContainer is saying it will handle whatever offer it is given, so when a new offer type ships, every host breaks at compile time rather than rendering a blank screen their users find first. A new offer type arriving in a catalog is something you have to decide about. Almost nothing in the config is per-offer. It is per-integration, so you build one object and pass the same one for every offer you render. The one exception is Ondo’s side, which is per-render. defaultCheckoutConfig({ ... }) fills in the entries that have a sensible default, so you only write the ones that do not. Today that is superstate::swap; it exists mostly so a provider that gains an optional setting can be defaulted there rather than appearing in every host’s config object.

Why symbol takes the offer

symbol is a function of the offer rather than a bare value because the symbol is per-asset while the config is per-integration: a host listing AAPLon and TSLAon side by side has one config and two answers. The SDK cannot answer it for you. Ondo’s symbol tracks the underlying ticker and changes on a rebrand, and it already disagrees with offer.asset.code on Sepolia, where a mock asset stands in. If your catalog does agree, return AssetSymbol(offer.asset.code); if it does not, map the exceptions.

Why side is a thunk

side takes no offer, because no offer can answer it. offer.type is ondo::swap in both directions - CoinList exposes one Ondo offer type, and the direction is a property of the page rather than of the catalog. Close the thunk over whatever selects it: a route, a tab, a prop. It is required with no default. The wire parameter behind it defaults to buy silently, and an unstated direction should be a compile error rather than a purchase.
side is read once, at mount. The Ondo flow holds a committed quote and an approval granted for one specific token, so a resolver that starts answering differently mid-flow is ignored rather than obeyed. Include the side in the container’s key, as “One mount, one offer, one chain” does for the offer and the chain.
symbol and side run only when an ondo::swap offer is showing. A Superstate or token-sale checkout never calls them, so symbol receives an OndoSwapOfferDetail and only has to answer for Ondo offers.

What happens underneath

CheckoutContainer switches on offer.type and mounts only the matching provider’s container, handing it the offer narrowed to its variant. Only that provider’s viewmodel runs, so the others fetch nothing and hold no timers. enabled is forwarded to the mounted container as-is: it pauses a checkout that is mounted but not on screen yet. The switch on offer.type is exhaustive, and its default branch assigns to const exhaustive: never, so a new offer type is a compile error inside the SDK as well as in your config.
Each product exposes a god viewmodel wrapping its entire flow, plus the smaller hooks it is built from. Call one behind your own markup when you want the SDK’s logic, state and error handling but not its UI.
offer is the narrowed variant: OndoSwapOfferDetail here and for useOndoSellCheckoutViewModel, which takes the same options, and SuperstateSwapOfferDetail for useSuperstateSwapCheckoutViewModel, which takes them minus ondoSymbol. All three return { state, onEvent }, where state is a discriminated union you switch on exhaustively - including an error arm, on both Ondo products, for an offer that cannot be swapped on the chain you passed.If you call these directly you are routing on offer.type yourself. Narrow the offer and call each viewmodel inside its own component, so only the matching one is mounted. That routing is exactly what CheckoutContainer does for you.Per-provider detail: Superstate Swap, Ondo Swap, CoinList Token Sale. The conventions the hooks share - enabled, data, and the shape of state - are in SDK structure.
Below the hooks are plain TypeScript namespaces on CoinListClient, with no React and no state. Use them for a non-React app, a custom state layer, or a step the SDK’s flows do not cover.
These return step-tagged results rather than throwing, so you can map each failure to your own copy. The full parameters, progress phases and error steps live on each provider’s page.

Next steps

Superstate Swap

Wallet allowlisting, live quotes, and what Superstate needs from you.

Ondo Swap

The symbol resolver, the side thunk, and what each direction approves.

CoinList Token Sale

The render slot, the approval, and tracking participations.

Errors and edge cases

Every error shape the flows return, and how to handle it.