Choose a Flow
| Flow | Sequence | When to use |
|---|---|---|
| Session-first | Create 3DS session -> complete 3DS -> create transaction | Use when your backend authenticates before transaction creation |
| Transaction-first | Create transaction (AWAITING_3DS) -> complete 3DS -> authenticate transaction | Use when your backend starts transaction orchestration first |
Both flows are official in Rinne. There is no platform-level preferred flow.
Backend Endpoint Mapping
| Context | Create session | Create transaction | Authenticate transaction |
|---|---|---|---|
| Self (company) | POST /v1/3ds-sessions | POST /v1/transactions | POST /v1/transactions/{transactionId}/authenticate |
| Merchant (organization on behalf) | POST /v1/merchants/{merchantId}/3ds-sessions | POST /v1/merchants/{merchantId}/transactions | POST /v1/merchants/{merchantId}/transactions/{transactionId}/authenticate |
Shared Frontend Setup
Session-First Flow
Create 3DS session on backend
Send the encrypted card number and plain expiry (month/year) from
mountedCard.values to your backend. The Card Element encrypts the card number client-side; expiry values are not encrypted.Backend session request example
Transaction-First Flow
In this flow, your backend transaction status determines whether frontend should run 3DS.
Create transaction and branch by status
Backend creates the transaction and returns the initial status.Use
require_3ds: true when you want deterministic AWAITING_3DS entry in transaction-first.Start 3DS only for AWAITING_3DS
If transaction is
AWAITING_3DS, create a 3DS session with the same amount/currency and encrypted card number/expiry.Mount challenge when required and authenticate
Branch on
auth_status: mount only for ACTION_REQUIRED, skip for AUTHENTICATED, abort for FAILED.
After challenge success (or if already AUTHENTICATED), backend authenticates the pending transaction with session id using:- Self:
POST /v1/transactions/{transactionId}/authenticate - Merchant:
POST /v1/merchants/{merchantId}/transactions/{transactionId}/authenticate
Challenge strategy flags (backend)
require_3ds: true: create directly inAWAITING_3DS, so you can enforce 3DS while staying on one transaction-first backend flow.refuse_on_challenge: true: fail fast withREFUSED+status_reason=CHALLENGE_NOT_ALLOWEDwhen a challenge-triggered path would occur.- Use
refuse_on_challengewhen you intentionally do not support challenge UX for a merchant, channel, or transaction segment. - The two flags cannot both be
true.
Transaction-first status branching
| Transaction status | Frontend/backend action |
|---|---|
AWAITING_3DS | Run 3DS session/challenge and call authenticate |
PROCESSING | Wait for webhook or status refresh; do not call authenticate yet |
AUTHORIZED / APPROVED | Payment already completed; continue normal success flow |
REFUSED + CHALLENGE_NOT_ALLOWED | Fail fast path triggered; no 3DS handling required |
REFUSED (other) | Regular decline flow |
If a transaction is initially
PROCESSING and later becomes AWAITING_3DS (for example, soft-decline recovery), run the same transaction-first 3DS steps at that point.Transaction-first orchestration example
Session ID Mapping
tds_session_id: use inthreeDSecure.mount(tds_session_id)on frontend.id: use asthree_d_secure_session_idin backend transaction create/authenticate calls.
Handle 3DS Statuses
In practice, sessions come back asACTION_REQUIRED or FAILED at creation — even frictionless authentication completes through the SDK element. The API contract allows AUTHENTICATED as a creation-time response for forward compatibility, so always branch on all three statuses.
auth_status at creation | Meaning | Frontend action |
|---|---|---|
ACTION_REQUIRED | Authentication required — mount the 3DS element | Mount 3DS element; the SDK handles frictionless and challenge internally |
FAILED | Card was rejected before the flow could start | Surface the error; let the user retry with a different card or payment method |
AUTHENTICATED | Frictionless authentication completed at creation time (rare) | Skip mounting; proceed directly to transaction creation or /authenticate |
Frictionless vs challenge
When the element is mounted, the issuer decides whether the transaction can be authenticated silently (frictionless) or needs cardholder interaction (challenge):- Frictionless: authentication completes in the background with no visible UI.
onSuccessfires automatically, often within seconds. - Challenge: an issuer-hosted verification step appears inside the element (OTP, app notification, biometric).
onSuccessfires after the user completes it.
onSuccess is the signal to proceed in either case. You can inspect authentication_flow on the backend after the session is authenticated to see which path was taken.
Retry Strategy
When a session expires or fails, request a new session and mount again.The SDK automatically unmounts previous 3DS instances when you remount with a new session ID.

