Skip to main content

Upsells & Offers

Three different APIs. Use the one that matches the moment in the journey: For the basic post-purchase funnel, use the first row only. The finished app is basic-post-purchase.
mainOrderId is the checkout order id (result.order.id from processPayment), never a payment id.

Get an Offer

Pin IDs from the dashboard or checkoutOffers.create (Node SDK). Do not pick “the first upsell” from listOffers — a store can have many.
listOffers({ type }) only filters upsell and orderbump. A downsell created with type: 'downsell' will not appear. Load it with getOffer(id).

One-click upsell (this is the OTO)

Preview the price, then charge the instrument stored on the main order. Prefer processOfferPayment — it runs 3DS / redirect / polling the same way payment.processPayment does.
Decline is not an API call on this path. Send them to the next URL yourself (/downsell?orderId= or /thank-you?orderId=).

Low-level: payPreviewedOffer

Returns the raw { payment, order, preview, checkout } and does not finish 3DS. Only use it if you handle payment.requireAction yourself. For a storefront, use processOfferPayment.
The accept does not add a line to the tee order. It creates a child order — and it lands asynchronously, a couple of seconds after the redirect. The SDK handles the wait for you:
See useOrder for the full thank-you page. Full graph: Basic post-purchase.

Order Bumps

Shown on checkout, before payment:
The parameter is orderBumpOfferId (not offerId).

Post-purchase offer list (not the OTO page)

listPostPurchaseOffers / acceptPostPurchaseOffer / declinePostPurchaseOffer are for “offers attached to this order” (account, email). They are not what the cap/tote pages in the basic funnel call.

React Hook

Full Hook API