Skip to main content
Use this guide to run card payments that may require 3D Secure, using either the session-first or transaction-first architecture. Both flows are officially supported. Choose the one that matches how your backend orchestrates transaction state and authentication.

Choose a Flow

Both flows are official in Rinne. There is no platform-level preferred flow.

Backend Endpoint Mapping

Shared Frontend Setup

Before processing card transactions, your merchant or organization must have an active Rinne card affiliation.
Use encrypted values from mountedCard.values only. Do not collect raw PAN/CVC in custom inputs.

Session-First Flow

1

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.
2

Run the 3DS challenge

Create threeDSecure once and call mount(tdsSessionId).
3

Create transaction after authentication

On onSuccess, call your backend and include the authenticated session ID.

Backend session request example

Transaction-First Flow

In this flow, your backend transaction status determines whether frontend should run 3DS.
1

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.
2

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.
3

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
4

Handle transaction result

Card transactions typically resolve synchronously — the /authenticate response already contains the final status (APPROVED, AUTHORIZED, or REFUSED). Use this status to drive your UI immediately.

Challenge strategy flags (backend)

  • require_3ds: true: create directly in AWAITING_3DS, so you can enforce 3DS while staying on one transaction-first backend flow.
  • refuse_on_challenge: true: fail fast with REFUSED + status_reason=CHALLENGE_NOT_ALLOWED when a challenge-triggered path would occur.
  • Use refuse_on_challenge when 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

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

Authenticate requests must use session id as three_d_secure_session_id. Do not send tds_session_id to your backend authenticate route.

Session ID Mapping

  • tds_session_id: use in threeDSecure.mount(tds_session_id) on frontend.
  • id: use as three_d_secure_session_id in backend transaction create/authenticate calls.

Handle 3DS Statuses

In practice, sessions come back as ACTION_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.

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. onSuccess fires automatically, often within seconds.
  • Challenge: an issuer-hosted verification step appears inside the element (OTP, app notification, biometric). onSuccess fires after the user completes it.
Your frontend code handles both identically — 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.