Skip to main content
Charge once on page 1, then charge again on page 2 without re-entering card details.
Current limitation: identifying upsell transactionsWidget upsells do not currently have a per-offer product name or label in the Paysight transaction view, and upsellId is not displayed there.The initial payment and each upsell appear as separate transaction entries. Both are labelled SINGLE PURCHASE, unless the customer opts into a subscription on the initial payment, which is labelled OPT IN. These labels do not identify the upsell or its position in the chain.For now, compare transaction amounts with your configured checkout and upsell prices to identify the initial payment and upsells 1, 2, 3, and so on. Offers with the same price cannot be reliably distinguished by amount alone.We are working on adding upsell labels/product names, but they are not available yet.

One product ID for the whole journey

Use the same Paysight productId for the initial checkout and every upsell. It identifies the Paysight payment configuration for the journey; it is not a separate catalog item ID for each offer. For every accepted upsell:
  1. Reuse that productId and the original initial payment’s PAYMENT_SUCCESS.payload.paysightSession as upsell.initialPaymentSession.
  2. Set usePreviousPaymentMethod: true and the upsell’s own amount.
  3. Give each different offer a unique, nonempty upsell.upsellId, such as upsell-1 or upsell-product-name. Keep that ID stable when retrying the same offer. Duplicate detection uses the offer ID together with the original session, so two offers must not share an ID.
  4. Charge only after acceptance: call widget.submitUpsell() from your host button, or use the built-in upsell button. Creating the widget does not charge the customer. Use submitPayment() for the initial checkout.
A second or third upsell still uses the initial checkout’s session, with a different offer ID and its own amount. Do not replace it with your host-generated sessionId or a later upsell response.

How the initial charge is priced

The Widget SDK requires amount. For normal card payments, its value determines whether the configured immediate charge is used: Each upsell can specify its own positive amount. Using amount: 0 to select a subscription immediate charge is counterintuitive, but it is the current behavior: the Paysight product selects the attached subscription configuration even for the initial payment.
Omitting amount fails SDK validation before a payment request is sent. To use the configured subscription immediate charge for a normal card payment, pass amount: 0. To override it, pass an amount greater than zero. Shopify cart mode instead computes its amount from cart lines and uses amount: 0 as its configuration placeholder.

Identifying the purchased offer

config.data.campaignName and config.data.affiliateName are forwarded on initial and upsell requests. However, the payment API reuses attribution for the same Paysight product and session: names are resolved only while their attribution IDs are unset. Changing names on an upsell does not reliably change the transaction’s campaign or traffic source. The transaction table exposes the resolved campaign and affiliate names, not necessarily the names supplied on the latest widget instance. Do not use campaignName as a reliable per-offer product label in an upsell chain. upsellId identifies the offer in widget events and duplicate detection. It is sent in payment props, but current transaction list/detail APIs do not expose it. Arbitrary config.data keys are forwarded too, but are not guaranteed to be persisted or returned as per-transaction metadata. If you need to distinguish purchased offers today, retain the offer ID and payment result in your own order records; Shopify cart flows additionally have cart product and variant identifiers.

Flow

Page 1 — checkout

savePaymentMethod applies to card, Apple Pay, and Google Pay.

Page 2 — upsell

Upsell is active when both upsell.upsellId and upsell.initialPaymentSession are set.
initialPaymentSession must be the paysightSession from page 1 PAYMENT_SUCCESS — not your sessionId.

External pay button on upsell

Keep the widget returned by createWidget. Set hidePaymentButton: true if you want only your host button; it is not required for submitUpsell():
See External payment button.

3DS on upsell

Set top-level 3DS flags on page 2, or override per upsell:

Events

Upsell charges emit the standard payment events. Use payload.mode to tell checkout from upsell.

Shopify variant

The same handoff works with Shopify cart mode on page 1. See Shopify cart checkout.

Live demo

Saved payment example — live demo at https://payment.paysight.io/demo?preset=upsell (sandbox).