How it works
- Your server creates a tokenization session and pins the net payable amount.
- The shopper enters their card; Elements tokenizes it (
elements.submit()). - The browser starts 3DS authentication (
threeDS.authenticate()), which may run frictionless or present a challenge. - Your server authorizes or purchases using the card token plus the 3DS reference. The gateway independently verifies the reference before it authorizes the charge.
Before you begin
Requires enablement on your account, a CSP that allows the 3DS iframe and
fetch origins — including your API origin in
connect-src, or a challenge
times out after 5 minutes instead of failing fast (see Content Security
Policy) — and Elements SDK v1.6.0 or
later.Steps
1
Create a payment session and pin the amount
Create a session as usual, then pin the amount that 3DS will authenticate
— this must be the amount you’ll actually charge, which may be lower than
the gross order amount if you redeem loyalty points.There’s no public
PATCH /v1/sessions/{id} reference page yet — see the
ThreeDS reference for how this step fits
the browser-driven flow. Keep ttl_minutes at 30 or less for a 3DS
checkout — see Token lifetime below.2
Tokenize the card in the browser
3
Authenticate with 3D Secure
4
Charge with the 3DS reference on your server
Send the token and the 3DS
ref from the browser to your server, then
purchase or authorize with three_ds:{ref} (API reference).Handle the result
Any 2xx response is a result you must branch onstatus — never on response_code (that’s the verbatim host/acquirer code; useful for support tickets, not for your app logic).
PENDING means the outcome isn’t known yet — most often after a processor timeout. Don’t assume success or failure. Recover it one of two ways:
- Wait for a webhook (
payment.*,authorization.*,refund.*— see Webhook event types). - Call
GET /v1/transactions/{id}/statusfor a live inquiry against the acquirer.
id yet — a client-side timeout before the first response arrived — replay the same request with the same request_id and body. The replay returns the stored transaction and its id, whatever status it’s reached. Never re-submit with a new idempotency key just because the first attempt is slow — that risks a second charge for the same order.
If the charge itself is rejected for a 3DS reason (for example
three-ds:ref-invalid or three-ds:ref-expired), see
Authentication results
for remedies, or Handle 3D Secure failures in Elements
for the recovery-action version of the same failures.
Server policy
Token lifetime
The card token fromelements.submit() is transient (about 30 minutes) and the
3DS authentication is bound to it. Keep ttl_minutes at 30 or less for a 3DS
checkout. If the token lapses or the shopper switches cards mid-flow:
- Before charging:
authenticate()rejects withthree-ds:card-token-invalid— re-bind the card (elements.submit()again) and re-authenticate. - At charge time: the purchase/authorize call rejects with
422 urn:radiumone:three-ds:card-token-mismatchif the charged token differs from the one that was authenticated — re-bind and re-authenticate rather than retrying the charge with the same ref.
Never use a secret key (
r1sk_…) in browser code, mobile apps, or anywhere a shopper can inspect it. Secret keys belong on your server only.Test your integration
See Test your integration for 3DS scenario coverage.Go-live notes
- Confirm your account has 3DS enabled before relying on this flow in production.
- Make sure your CSP allows the 3DS iframe/fetch origins — see Content Security Policy.
- Review the go-live checklist before launch.
Next steps
Challenge presentation and redirects
Customize where the challenge renders, and handle redirect return pages.
Authentication results
Every status, ECI value and 3DS error remedy.