A naive off-session attempt without prior setup is significantly less likely to succeed. To combat this, Stripe looks for the first successful on-session transaction with the card, then references it — proving same merchant, same amount, approved, no chargeback.

FactorOn-SessionOff-Session
CVVRequires the physical card; PCI standards forbid vaultingNot available — customer not present
3DSOut-of-band authentication between cardholder and issuerCannot complete — no browser to redirect
CaptchaStripe may request additional verificationNot possible without user interaction
Net EffectThese factors differentiate our payment attempt from fraudulent requestsWithout prior on-session success, the charge looks indistinguishable from fraud
Simple Integration
  1. User goes through checkout on-session. 2. Initial payment is collected. 3. At renewal, Stripe references that original payment. 4. Off-session payment succeeds.
SetupIntent Integration

When payment isn't required at checkout (e.g. free trials), we need credentials set up for future off-session use. SetupIntents create a real $0 authorization request sent to the card network. If successful, this on-session authorization can be referenced off-session.

A saved card doesn't guarantee the charge succeeds without interaction. The issuer might require 3DS on the PaymentIntent — a separate decision from whether 3DS was needed to save the card. When Stripe requires 3DS, it transitions the PaymentIntent into requires_action and provides a redirect link. This transition will not happen when off_session=true — instead, the payment fails.

What We Need

A payment method on file before calling subscriptions-api. The subscription needs to be created and the first invoice charged without further user interaction.

What Breaks

When Stripe requires 3DS on the PaymentIntent, it returns requires_action with a redirect URL. But subscriptions-api is making this call server-side — there's no browser to redirect.

The solution: subscribe first, collect payment with the customer present. Users can initiate subscription changes without a payment method on file. Instead of charging server-side, subscriptions-api returns the PaymentIntent's client_secret to the frontend. Dashboard uses the client secret to confirm via Stripe.js. If 3DS is required, the customer is right there.

Subscribe Return client_secret Frontend Confirms 3DS (if needed) Payment Succeeds
FrameworkDescriptionRelevance
3DS ProtocolCreated by Visa (c. 2001). The acquirer (Stripe) asks the issuer for a redirect link. The customer authenticates directly with the issuer, usually via OTP.On-session authentication factor
SCA (Strong Customer Authentication)Requires many online card payments go through another-factor authentication. Provides exemptions for recurring and merchant-initiated transactions.EU/EEA regulatory requirement
RBI e-mandatesRequires customer consent (an e-mandate) prior to saving a credit card. AFA must be used while collecting this consent, hence 3DS in on-session flows.India regulatory requirement