One-Click Upsells, Downsells & Instant Purchases

Available via: API (private key). The initial card collection can be done with the SDK or server-to-server.

Introduction

One-click upsells, downsells, post-purchase offers, and instant purchases all rely on the same capability: charging a payment method that the customer has previously saved, without asking them to enter their card details again.

On Inflow, this is achieved by creating a server payment with the useCustomerPaymentMethod parameter set to true. This guide covers the complete integration:

  1. Save the payment method during the initial purchase
  2. Verify that the customer has a saved payment method
  3. Create the one-click payment
  4. Confirm the payment

How It Works

Two parameters of POST /api/server/payment control this flow:

ParameterWhen to use itEffect
savePaymentMethod: trueOn the initial paymentThe card used for the payment is saved and linked to the customer's email (customerEmail).
useCustomerPaymentMethod: trueOn subsequent paymentsThe payment is charged to the customer's saved card. No card details are collected.

The saved payment method is identified by the customer's email address. For the one-click charge to succeed, the subsequent payment must use the same customerEmail and the same currency as the saved card.

A typical upsell funnel therefore looks like this:

  1. The customer completes an initial purchase and their card is saved.
  2. Your application presents an additional offer (upsell).
  3. If the customer accepts, your backend charges the saved card in a single API call — no card form is displayed.
  4. If the customer declines, you may present a cheaper alternative (downsell) and charge it the same way.

Step 1: Save the Payment Method During the Initial Purchase

A one-click charge requires an existing saved payment method. There are three ways to obtain one, depending on how you collect card details:

IntegrationHow to save the cardDocumentation
SDK card form (recommended for web funnels)Create the initial payment with savePaymentMethod: true, then mount the SDK CardElement as usual. The SDK handles tokenization, 3D Secure, and confirmation.React, Vanilla JS
Full server-to-serverAdd savePaymentMethod: true to your standard S2S payment creation call on https://api-card.inflowpay.com.Server-to-Server Payments
Card setup without a charge (signup, free trial)Create a no-charge PaymentSetup and complete it with the SDK.Free Trial & Card Setup

Customer consent (SDK integrations)

When savePaymentMethod: true is set, the SDK card form displays a "save my card" checkbox to the customer. The card is only saved if the customer checks this box.

If your funnel depends on the card always being saved — for example, when the upsell step is a core part of your flow — contact [email protected] to enable card saving without the consent checkbox on your account.


Step 2: Verify That the Customer Has a Saved Payment Method

Before presenting a one-click offer, confirm that the customer actually has a saved payment method. Attempting a useCustomerPaymentMethod payment for a customer without one results in an error (see Error Handling).

You have two options:

Option A — Webhooks (recommended). Listen for payment.* success events (card saved during a payment) or payment_setup.completed (card saved without a charge), and record in your database that the customer has a saved payment method. See Webhooks.

Option B — On-demand lookup. Query the API at the time of the offer. Note that the list endpoint takes the customer id (cus_...), not the email, so resolve the id first:

# 1. Resolve the customer id from the email
curl "https://api.inflowpay.xyz/api/customer/email/{customerEmail}" \
  -H "X-Inflow-Api-Key: your_private_key"

# 2. List the saved payment methods for the relevant currency
curl "https://api.inflowpay.xyz/api/customer/{customerId}/payment-methods?currency=EUR" \
  -H "X-Inflow-Api-Key: your_private_key"

API reference: GET /api/customer/email/{email}, GET /api/customer/{customerId}/payment-methods.


Step 3: Create the One-Click Payment

When the customer accepts the offer, create a payment with useCustomerPaymentMethod: true. The request must respect three rules:

  • Same customerEmail as when the card was saved.
  • Same currency as the saved card — a card saved for EUR cannot be charged in USD.
  • No card data and no save flag — do not send card, tokenIntentId, or savePaymentMethod. Combining savePaymentMethod or tokenIntentId with useCustomerPaymentMethod returns a 400 error; a card object is ignored.

Product prices are expressed in cents (1999 = €19.99), as everywhere in the API.

curl -X POST https://api.inflowpay.xyz/api/server/payment \
  -H "X-Inflow-Api-Key: your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [{ "name": "Premium Add-on", "price": 1999, "quantity": 1 }],
    "currency": "EUR",
    "customerEmail": "[email protected]",
    "billingCountry": "FR",
    "purchasingAsBusiness": false,
    "useCustomerPaymentMethod": true,
    "metadatas": { "funnelStep": "upsell_1" }
  }'

This call uses the standard base URL https://api.inflowpay.xyz. The api-card.inflowpay.com base URL is only required when transmitting raw card data, which is not the case here.

Response

{
  "id": "pay_def456",
  "amountInCents": 1999,
  "currency": "EUR",
  "status": "CHECKOUT_PENDING",
  "depositStatus": "requires_confirmation",
  "customerEmail": "[email protected]",
  "customerPaymentMethod": {
    "id": "cpm_abc123",
    "type": "card",
    "cardBrand": "visa",
    "cardLast4": "4242"
  }
}

Unlike a new-card payment (returned with status INITIATION), a saved-card charge is prepared during creation. The payment is therefore returned with status CHECKOUT_PENDING and depositStatus: "requires_confirmation" — it is waiting for your confirmation call.


Step 4: Confirm the Payment

autoConfirm does not apply to this flow. A payment created with useCustomerPaymentMethod: true is never confirmed automatically. You must always call the confirm endpoint — if this step is skipped, the customer is never charged.

curl -X POST https://api.inflowpay.xyz/api/server/payment/{paymentId}/confirm \
  -H "X-Inflow-Api-Key: your_private_key"

API reference: POST /api/server/payment/{paymentId}/confirm.

After confirmation, track the final payment status through webhooks (payment.* events) rather than polling. A charge on a saved card can still be declined by the customer's bank — handle payment.failed events and offer a card re-entry fallback in that case.


Implementing a Downsell

A downsell is technically identical to an upsell: only your funnel logic differs. If the customer declines the initial offer, present a cheaper alternative and repeat Step 3 and Step 4 with different products (for example with "funnelStep": "downsell_1" in metadatas).

You can chain as many one-click offers as your funnel requires — each one is an independent payment.


Rules and Limitations

RuleDetail
Mutually exclusive parameterssavePaymentMethod and useCustomerPaymentMethod cannot both be true in the same request (400 error). Either you save a new card, or you use an existing one.
Same customerEmailThe saved card is tied to the customer's email for your account. The one-click payment must use the exact same customerEmail as when the card was saved.
Currency must matchEach saved card is linked to a currency. A useCustomerPaymentMethod payment in EUR requires a card saved for EUR.
Last saved card is chargedIf a customer saves multiple cards over time, the most recently saved one becomes the default and is charged. Selecting a card per payment is not supported, but the default card can be changed with set-default.
No card fields allowedSending tokenIntentId together with useCustomerPaymentMethod: true returns a 400 error; a card object is ignored.
Confirmation is a separate callautoConfirm is ignored — always call POST /api/server/payment/{paymentId}/confirm.

Error Handling: No Saved Payment Method

If the customer has no saved payment method for the requested currency, the payment creation fails with:

"couldn't process payment in the useCustomerPaymentMethod context, the customer [email protected] has no payment method for currency EUR"

In this case, fall back to collecting the card normally: display the SDK card form with savePaymentMethod: true (so that the next offer can be one-click), or send the customer through a PaymentSetup.

Best Practices

  • Store your funnel context (offer id, step, campaign) in metadatas — it is returned on the payment object and in webhook payloads.
  • Check for a saved payment method before rendering the one-click button, so that customers without a saved card never trigger the error above.
  • One-click charges also work for subscriptions: useCustomerPaymentMethod is available on subscription initiation.