Series: Running a Subscription Business · Part 3 of 4
- Peak Trading Readiness: How We Prepare a Subscription Platform for Valentine's Day
- Involuntary Churn: The Engineering Behind Recovering Failed Subscription Payments
- SCA, 3D Secure 2 and Recurring Payments: An Architect's Guide for Subscription Platforms
- Winning the Pennies Unsung Hero Award: What Micro-Donations Mean in Tech
Contents
Why Subscription Businesses Have to Care
Strong Customer Authentication (SCA) under PSD2 has been enforced for e-commerce across most of the EEA since early 2021 and in the UK since March 2022. For one-off purchases it mostly means a customer occasionally approves a payment in their banking app. For subscription businesses it goes deeper, because most of our payments happen when the customer is not there.
Getting the architecture right means understanding three things: when authentication is required, how to set up recurring payments so future charges don't need it, and how to keep your own systems out of PCI DSS scope while you do all this.
What SCA Actually Requires
SCA requires two of three independent factors for customer-initiated electronic payments:
- Knowledge: something the customer knows (a password or PIN)
- Possession: something they have (a phone or card reader)
- Inherence: something they are (a fingerprint or face)
For card payments online, the mechanism is 3D Secure. 3DS1, with its clunky redirects and static passwords, was retired by the schemes in 2022. What we use now is EMV 3DS (3DS2), which sends the issuer much richer data about the transaction and device. That lets the issuer approve many transactions in a frictionless flow with no customer interaction, and reserve a challenge flow for the ones it considers risky.
A useful side effect: when a payment is authenticated through 3DS, fraud chargeback liability generally shifts from the merchant to the issuer.
Out of Scope vs Exempt
This distinction trips up a lot of teams. Some transactions are out of scope of SCA entirely; others are in scope but exempt if someone requests the exemption and the issuer accepts it.
| Category | Type | When it applies | Who decides |
|---|---|---|---|
| Merchant-initiated transactions (MIT) | Out of scope | Customer is not present; charge made under an agreement authenticated earlier | Treated as outside SCA, flagged as MIT |
| MOTO | Out of scope | Mail and telephone orders | Outside SCA |
| One-leg-out | Out of scope (best efforts) | Issuer or acquirer outside the UK/EEA | Outside SCA |
| Low value | Exemption | Up to €30, with cumulative limits of €100 or five transactions since last SCA (the UK applies sterling equivalents) | Issuer |
| Transaction risk analysis (TRA) | Exemption | Low-risk remote payments, with thresholds tied to the PSP's fraud rate | Acquirer or issuer, issuer has final say |
| Recurring, same amount | Exemption | Series of payments of the same amount to the same payee, after the first is authenticated | Issuer |
| Trusted beneficiary | Exemption | Customer has added the merchant to a trusted list with their bank | Issuer |
| Secure corporate payments | Exemption | Dedicated corporate processes and protocols | Issuer |
For TRA, the thresholds are €100, €250 and €500 for remote card payments, depending on whether the PSP's fraud rate is below 13, 6 or 1 basis points respectively. The key point for architects: an exemption is a request. The issuer can always decline it and ask for authentication, and your system needs to handle that gracefully.
How Recurring Payments Work Under SCA
For a subscription, the pattern is:
- Authenticate the first payment, or a zero-amount card setup, on-session. This is where the customer agrees to be charged in future and completes 3DS if the issuer asks.
- Store the credential with the right flags, so the network knows this is a stored credential for a recurring or unscheduled agreement.
- Make future charges as MITs, referencing the original authenticated transaction. These are out of scope of SCA.
Most payment providers wrap this up for you. Stripe's API is a clear illustration:
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string);
// On-session: customer is present, 3DS may be triggered
const setupIntent = await stripe.setupIntents.create({
customer: customerId,
payment_method_types: ['card'],
usage: 'off_session',
});
// Later, off-session: a merchant-initiated charge
try {
await stripe.paymentIntents.create({
amount: 3500,
currency: 'gbp',
customer: customerId,
payment_method: paymentMethodId,
off_session: true,
confirm: true,
});
} catch (err) {
if (err instanceof Stripe.errors.StripeCardError && err.code === 'authentication_required') {
// Issuer wants SCA: bring the customer back on-session
}
}Adyen expresses the same idea with shopperInteraction: 'ContAuth' and a recurringProcessingModel of Subscription, CardOnFile or UnscheduledCardOnFile. Braintree has equivalent transaction source flags. The names differ; the model is the same.
The part people get wrong
Even with correct MIT flagging, some issuers will still decline an off-session payment with a request for authentication. That is not a bug. Your system needs a path for it: pause the charge, email the customer a secure link, complete 3DS on-session and then take the payment. In a subscription business this belongs in the same recovery flow as other failed payments.
Two other design decisions matter:
- Changing the amount. A variable-amount subscription is fine as MIT, but the original mandate should describe how charges can vary. If you change the terms materially, re-authenticate.
- Changing the card. A new card needs a new on-session authentication before you can use it off-session.
Keeping PCI DSS Scope Small
PCI DSS v3.2.1 was retired on 31 March 2024, so v4.0 is now the only version you can assess against. It brings a set of future-dated requirements that are best practice today and become mandatory on 31 March 2025. If you haven't planned for them, now is the time.
The most effective thing a merchant can do is never let raw card data touch their systems. The options, roughly in order of scope:
| Approach | How it works | Typical SAQ | Trade-offs |
|---|---|---|---|
| Full redirect to hosted payment page | Customer leaves your site to pay | SAQ A | Smallest scope; least control over UX |
| Hosted fields or embedded iframe | Card inputs are iframes served by the PSP | SAQ A | Small scope; good UX; parent page scripts now matter |
| Direct post / JavaScript that handles card data | Your page posts card data to the PSP | SAQ A-EP | Your web servers are in scope |
| API integration with raw card data | Card data passes through your servers | SAQ D | Full scope; rarely justified |
With hosted fields, the PSP returns a token and your backend only ever deals with tokens. That is how I'd advise any subscription business to build.
The v4.0 change to watch here is payment page script security. Requirement 6.4.3 asks you to inventory, authorise and assure the integrity of every script on the payment page, and requirement 11.6.1 asks you to detect unauthorised changes to the page and its security headers. Both are future-dated to 31 March 2025, and the v4.0 SAQ A includes them for merchants whose pages embed a PSP's iframe. In practice that means a strict Content Security Policy on checkout pages, keeping third-party tags off them, and some form of change detection. It is a good reason to keep checkout pages lean.
Advice by Situation
- Launching a subscription product: use your PSP's hosted fields and its recurring payments API. Let it handle 3DS, MIT flagging and credential storage.
- Migrating from a legacy integration: check that historic stored credentials were set up with proper agreements; you may need to re-authenticate some customers. Build the "authentication required" recovery path before you migrate.
- Operating at scale: work with your PSP on TRA exemptions and track authentication and challenge rates as first-class metrics. Plan the v4.0 script-security controls now rather than in March 2025.
The Takeaway
For subscriptions, SCA is mostly a one-time cost at sign-up: authenticate once on-session, flag future charges correctly as merchant-initiated, and build a clean path for the issuers who ask for authentication anyway. Pair that with hosted fields and tokenisation to keep PCI DSS scope small, and start on the v4.0 script-security requirements before the March 2025 deadline.
