3D Secure
3D Secure (3DS) is an authentication step that runs before a card payment is authorized. The cardholder's issuing bank verifies that the person making the purchase is the legitimate cardholder—either silently (frictionless) or by presenting a challenge such as a one-time passcode or a banking-app push.
Credova implements 3DS 2.x using Basis Theory as the 3DS Server and passes the resulting authentication values to the processor on a single payment submission. 3DS layers onto the existing Payment Intents flow and provides you the flexibility to opt in per intent at confirm time.
Why use it: a successful 3DS authentication shifts chargeback liability from you to the issuer and is mandatory for Strong Customer Authentication (SCA) on in-scope EU/UK transactions.
Transports
There are two ways to present 3DS to the cardholder. Both share the same confirm → complete API flow and differ only in how the session is created and how a challenge is rendered.
| Factor | Iframe | Redirect |
|---|---|---|
| Session created | In the browser, via the Elements SDK | Server-side, by Credova at confirm |
| Device fingerprint quality | Real (browser-collected) — higher frictionless rate | Approximated — lower frictionless rate |
| Challenge presentation | ACS iframe embedded in your page (state preserved) | Full-page navigation to a hosted page |
| Merchant routes required | None | Two callback routes (success + failure) |
| JS SDK dependency | Required (@publicsquare/elements-js / -react) | None |
| Mobile webview compatibility | Can be blocked by some webviews | Universal |
| Best for | Standard web checkouts (default) | Native webviews, server-rendered checkouts |
See Process 3DS Payments (Iframe) and Process 3DS Payments (Redirect) for step-by-step walkthroughs.
Glossary
| Term | Meaning |
|---|---|
| 3DSS | 3DS Server — initiates authentication on the merchant's behalf (Basis Theory) |
| ACS | Access Control Server — the issuer's challenge endpoint |
| Frictionless | Authentication completes with no cardholder interaction |
| Challenge | Cardholder must complete an ACS-hosted step (OTP, biometric, bank app) |
| Liability shift | Chargeback liability moves from merchant to issuer on success |
Anatomy
Confirm request
Send the three_d_secure field as part of the confirm call. See Confirm Payment Intent for more details.
| Field | Description |
|---|---|
transport | Required. iframe or redirect. |
session_id | Iframe only. The Credova 3DS session id (id) returned by the Elements SDK createSession. |
success_url | Redirect only. Where the cardholder is returned after a successful challenge. |
failure_url | Redirect only. Where the cardholder is returned on a failed/cancelled challenge. |
challenge_preference | Optional. See Challenge preference. |
exemption_request_reason | Required when challenge_preference is exemption-requested. See Challenge preference. |
Next action
When a challenge is required, confirm returns the intent in requires_action status with
| Field | Description |
|---|---|
session_id | The 3DS session id. Pass this back to complete. |
transport | iframe or redirect. |
acs_challenge_url | Iframe only. URL the SDK loads to render the challenge. |
acs_transaction_id | Iframe only. Identifies the ACS transaction for the SDK. |
three_ds_version | Iframe only. The 3DS protocol version, e.g. 2.2.0. |
redirect_url | Redirect only. Navigate the browser here to present the challenge. |
3DS session
Created in the browser by the Elements SDK createSession (which also registers it with Credova) and retrievable via Get 3DS Session.
| Field | Description |
|---|---|
id | The Credova session id. Pass this to confirm and complete. |
bt_session_id | The underlying session id used to render the challenge iframe (the SDK challenge sessionId). |
card_brand | Detected card brand. |
additional_card_brands | Any co-badged brands. |
acs_transaction_id | ACS transaction identifier. |
{
"id": "tds_2YKewBonG4tgk12MheY3PiHDy",
"bt_session_id": "0e5a...c1",
"card_brand": "visa",
"additional_card_brands": ["cartes_bancaires"],
"acs_transaction_id": "f3e8a1b2-..."
}
id drives the confirm/complete API calls, and bt_session_id drives the in-page challenge.Lifecycle
The issuer returns one of these authentication status codes. Codes that authenticate the cardholder allow the payment to proceed to the processor; the rest fail the payment.
| Code | Meaning | Outcome |
|---|---|---|
Y | Successful | Authenticated — full liability shift, payment proceeds |
A | Attempted | Authenticated — no liability shift, payment proceeds |
I | Informational | Authenticated — payment proceeds |
C | Challenge required | Render the challenge, then call complete |
N | Not authenticated | Payment fails |
U | Unable to authenticate | Payment fails |
R | Rejected | Payment fails |
Challenge preference
challenge_preference lets you express how you'd like the issuer to handle the authentication. Most integrations omit it (defaults to no preference).
| Value | Use when |
|---|---|
no-preference | Standard transaction, no specific exemption requested. |
no-challenge | You'd prefer a frictionless flow but aren't claiming a regulatory exemption. |
challenge-requested | You want to force a challenge (e.g. high-ticket transactions). |
exemption-requested | You're claiming a regulatory SCA exemption. Requires exemption_request_reason. |
When challenge_preference is exemption-requested, set exemption_request_reason to one of: low-value-payment, transaction-risk-analysis, add-card, account-verification.
Testing
3DS authentication is triggered by the test card number you use. See 3D Secure test cards for every scenario, from frictionless success to a failed challenge.
Where to go next
- Process 3DS Payments (Iframe) — in-page challenge with the Elements SDK
- Process 3DS Payments (Redirect) — hosted challenge via full-page redirect
- Confirm Payment Intent — API reference
- Complete Payment Intent 3DS Challenge — API reference
- Get 3DS Session — API reference