3DS Integration at Tuna#
Tuna has its own MPI (Merchant Plug-In) powered by Cybersource/Cardinal Cruise (Visa), which means you don't need to integrate with an external MPI provider. The 3DS authentication layer is handled transparently by Tuna's platform.
3DS is activated on a per-merchant basis, according to each customer's risk and conversion strategy. The decision to use 3DS, and for which payment flows, is configured in Tuna Console's no-code flow editor. If you need help enabling or tuning 3DS for your account, contact your Account Manager or the Tuna Support team.
Not sure which integration mode to use?
If you use Tuna Checkout (hosted payment link or embedded), skip to the Tuna Checkout section — just configure your flow.
If you are on VTEX, skip to the VTEX section — it only takes one step. For all other platforms, choose one of the four direct integration modes below.
How 3DS works at Tuna#
The three fields your backend must pass to Payment/Init inside authenticationInformation:
| Field | Source | Description |
|---|---|---|
code | Returned by 3DS setup / Token/Generate | The same code sent to Generate in Token |
referenceId | Returned by 3DS setup / Token/Generate | Cardinal/Cybersource reference ID |
transactionId | Returned by 3DS setup / Token/Generate | Cardinal/Cybersource transaction ID |
Integration modes#
There are four integration approaches available in our official Postman collection. Choose the one that fits your architecture:
| Mode | Who tokenizes? | Who calls Payment/Init? | Best for |
|---|---|---|---|
| 3DS with pure JS | Your frontend form | Your backend | Full control, custom UI |
| 3DS using tuna.js for tokenization | tuna.js (frontend) | Your backend | Simplify PCI scope on frontend |
| 3DS using tuna.js for all interactions | tuna.js (frontend) | tuna.js (frontend) | Fastest integration, full delegation |
| 3DS with manual tokenization | Your frontend (JS) | Your backend | Direct control over card capture and tokenization |
Step 1 — Create a session (all modes)#
The first step is always the same regardless of integration mode: create a Token session via your backend.
note
Always create sessions from your backend — never expose your apptoken on the frontend.
- Request
- Response
Set
Is3dsTest: truewhile testing in the sandbox. Remove it (or set tofalse) in production.
Store the sessionId — it is passed as TokenSession in all subsequent calls.
Mode 1: 3DS with pure JS#
Your frontend handles card capture (using a custom form or any card entry UI). Your backend then calls Payment/Init with the 3DS auth data obtained from the frontend.
How to use the Tuna sample form#
Open the Tuna-hosted sample for this mode:
- Enter the
sessionIdyou obtained in Step 1. - Fill in the card details (use a Cybersource test card — see test cards below).
- The form runs the 3DS device data collection and authentication challenge.
- On success it displays the
token,code,referenceId, andtransactionId. - Copy those values into your Postman
Init / CreditorInit / Debitrequest.
Backend: Call Payment/Init#
After the frontend completes, your backend calls POST https://engine.tunagateway.com/api/Payment/Init:
- Credit (paymentMethodType 7)
- Debit (paymentMethodType 8)
Mode 2: 3DS using tuna.js for tokenization#
tuna.js handles card field rendering, device data collection, and 3DS authentication on the frontend. It returns the token, code, referenceId, and transactionId to your page. Your backend then calls Payment/Init.
How to use the Tuna sample form#
👉 tuna.js tokenization sample form
- Provide the
sessionIdfrom Step 1. - tuna.js renders the card fields and handles 3DS transparently.
- On completion it returns the authentication data you need for
Payment/Init. - Pass those values to your backend, which calls
Payment/Initusing the same request structure as Mode 1 above.
Adding tuna.js to your page#
Initialize with the sessionId from your backend and configure 3DS:
See the full tuna.js documentation for all configuration options.
Mode 3: 3DS using tuna.js for all interactions#
tuna.js handles the complete flow: card entry, 3DS authentication, and the Payment/Init call — all from the browser. Your backend only needs to create the session.
note
Because tuna.js calls Payment/Init from the frontend in this mode, the session must be created with the full order data (amount, items, etc.) — not just customer data.
How to use the Tuna sample form#
👉 tuna.js full-flow sample form
- Your backend creates a
NewSessionincluding thePaymentAccountandpartneruniqueid. - Return the
sessionIdto the frontend. - tuna.js renders the checkout, performs 3DS, and submits the payment.
- Poll the Payment Status API or listen to webhooks to confirm the outcome.
For the Postman collection, this mode only requires the NewSession call — tuna.js takes over from there.
Mode 4: 3DS with manual tokenization#
In this mode your frontend calls Token/Generate directly using JavaScript, and your backend calls Payment/Init. This gives you full control over the card capture form while keeping sensitive card data off your backend.
PCI DSS requirement
Token/Generate — and any API that handles raw card data — must be called from the browser (frontend JS), not from your backend server, unless your company holds a PCI DSS Level 1 certification. Routing card numbers through your backend without Level 1 certification puts you out of PCI scope.
This is why NewSession is always called from the backend (it only handles non-sensitive identifiers), while Token/Generate is called from the frontend.
Step 1: Create session (already covered above)#
Step 2: Tokenize the card with 3DS code (frontend JS)#
Your frontend calls POST https://token.tunagateway.com/api/Token/Generate via JavaScript, passing the card data and the 3DS Code from the Cardinal/Cybersource payer auth setup:
- Request
- Response
The returned token is used in Payment/Init. The code, referenceId, and transactionId for authenticationInformation are provided by the Cardinal/Cybersource 3DS authentication response on the frontend.
Step 3: Call Payment/Init#
Use the same Payment/Init request structure as Mode 1, with the token from Token/Generate and the authenticationInformation fields from the 3DS frontend flow.
Providing browser/device data#
For all modes, passing frontData in Payment/Init is strongly recommended when using 3DS. It enables more accurate risk assessment and better frictionless rates:
| Field | Description |
|---|---|
useragent | Browser User-Agent header |
IpAddress | Cardholder IP address |
acceptheader | HTTP Accept header |
acceptlanguage | Browser language (IETF BCP47) |
colorDepth | Screen color depth in bits |
screenHeight / screenWidth | Screen dimensions in pixels |
timeDifference | UTC offset in minutes (e.g. -180 for BRT) |
javaEnabled | "Y" or "N" |
javaScriptEnabled | "Y" or "N" |
VTEX#
For VTEX merchants, 3DS is enabled out of the box. All you need to do is install Tuna's VTEX IO app:
Install it from the VTEX App Store or via the VTEX IO CLI:
After installation, follow the standard Tuna VTEX plugin setup to configure your Gateway Affiliation and credentials. There is no additional 3DS configuration required — Tuna handles authentication automatically based on your flow settings in Tuna Console.
Headless & mobile apps on VTEX
Tuna has partnerships with the leading headless and mobile implementors in the VTEX ecosystem. 3DS is fully supported in storefronts built by Compra Rápida, Trinio, and Kobe. If your storefront runs on one of these platforms, contact your implementor or your Tuna Account Manager to enable 3DS.
Tuna Checkout#
If you use Tuna Checkout — whether as a hosted payment link shared externally or embedded in your page via iframe — 3DS is supported out of the box with no additional integration work.
All you need is the flow configuration in Tuna Console (no-code flow editor) to enable 3DS for the relevant payment methods. Tuna Checkout will handle the full authentication challenge flow automatically, including device data collection and the redirect/embedded challenge UI.
If you need help setting up your flow to include 3DS, contact your Account Manager or the Tuna Support team.
Cybersource test cards#
Tuna's MPI runs on Cybersource/Cardinal Cruise. Use the test cards below in the sandbox environment.
How to use test cards#
- Replace every
Xin the card number with0(zero). - Use expiration month: January (01) and expiration year: current year + 3 (e.g., for 2026 use
01/2029). - Any CVV (e.g.,
123) works in the sandbox.
Visa (Card Type = 001) — most common for Brazilian merchants#
| Scenario | 3DS 2.2 Test Card | Enroll result | Validation result |
|---|---|---|---|
| 2.1 Frictionless — authentication successful | 4XXXXX XX XXXX 27X1 → 4000000000002701 | RC=100, VERes=Y, PARes=Y, ECI=05 (vbv) | No challenge required |
| 2.2 Frictionless — authentication unsuccessful | 4XXXXX XX XXXX 4574 → 4000000000004574 | RC=476, VERes=Y, PARes=N, ECI=07 | — |
| 2.3 Stand-in — attempted | 4XXXXX XX XXXX 2719 → 4000000000002719 | RC=100, VERes=Y, PARes=A, ECI=06 (vbv_attempted) | — |
| 2.4 Frictionless — authentication unavailable | 4XXXXX XX XXXX 2313 → 4000000000002313 | RC=100, VERes=Y, PARes=U | — |
| 2.5 Frictionless — authentication rejected | 4XXXXX XX XXXX 2537 → 4000000000002537 | RC=476, VERes=Y, PARes=R | — |
| 2.6 Authentication not available (system error) | 4XXXXX XX XXXX 299X → 4000000000002990 | RC=100, VERes=U | — |
| 2.7 Check enrollment error | 4XXXXX XX XXXX 2446 → 4000000000002446 | RC=100, VERes=U | — |
| 2.8 Timeout | 4XXXXX XX XXXX 2354 → 4000000000002354 | RC=100, VERes=U | — |
| 2.9 Step-up — challenge successful | 4XXXXX XX XXXX 25X3 → 4000000000002503 | RC=475, VERes=Y, PARes=C | RC=100, PARes=Y, ECI=05 (vbv) |
| 2.10 Step-up — challenge unsuccessful | 4XXXXX XX XXXX 4293 → 4000000000004293 | RC=475, VERes=Y, PARes=C | RC=476, PARes=N |
Mastercard (Card Type = 002)#
| Scenario | 3DS 2.2 Test Card | Enroll result |
|---|---|---|
| 2.1 Frictionless successful | 52XXXX XX XXX 2235 → 5200000000002235 | RC=100, VERes=Y, PARes=Y, ECI=02 (spa) |
| 2.2 Frictionless unsuccessful | 52XXXX XX XXXX 2276 → 5200000000002276 | RC=476, VERes=Y, PARes=N |
| 2.3 Stand-in attempted | 52XXXX XX XXXX 2482 → 5200000000002482 | RC=100, VERes=Y, PARes=A, ECI=01 (spa) |
| 2.9 Step-up successful | 52XXXX XX XXXX 2151 → 5200000000002151 | RC=475, PARes=C; validation RC=100, ECI=02 |
Elo (Card Type = 054)#
| Scenario | 3DS 2.2 Test Card | Enroll result | Validation result |
|---|---|---|---|
| 2.1 Frictionless — authentication successful | 65X529 XX XXXX 2XXX → 6505290000002000 | RC=100, VERes=Y, PARes=Y, ECI=05 (cs) | No challenge required |
| 2.2 Frictionless — authentication unsuccessful | 65X529 XX XXXX 2X18 → 6505290000002018 | RC=476, VERes=Y, PARes=N, ECI=07 | — |
| 2.3 Stand-in — attempted | 65X529 XX XXXX 2026 → 6505290000002026 | RC=100, VERes=Y, PARes=A, ECI=06 (cs_attempted) | — |
| 2.4 Frictionless — authentication unavailable | 65X529 XX XXXX 2X34 → 6505290000002034 | RC=100, VERes=Y, PARes=U | — |
| 2.5 Frictionless — authentication rejected | 65X529 XX XXXX 2X83 → 6505290000002083 | RC=476, VERes=Y, PARes=R | — |
| 2.9 Step-up — challenge successful | 65X529 XX XXXX 219X → 6505290000002190 | RC=475, VERes=Y, PARes=C | RC=100, PARes=Y, ECI=05 (cs) |
ECI value reference#
The ECI (E-Commerce Indicator) value in the enrollment/validation response indicates the authentication outcome:
| Network | Successful auth ECI | String value | Attempted ECI | Failed ECI |
|---|---|---|---|---|
| Visa | 05 | vbv | 06 (vbv_attempted) | 07 |
| Mastercard | 02 | spa | 01 | 00 |
| Amex | 05 | aesk | 06 (aesk_attempted) | 07 |
| Elo | 05 | cs | 06 (cs_attempted) | 07 |
| Discover | 05 | dipb | 06 (dipb_attempted) | 07 |
Interpreting test results#
PARes status | Meaning | Action |
|---|---|---|
Y | Authentication successful | Proceed with authorization — full liability shift |
A | Attempted (stand-in) | Proceed with authorization — partial liability shift |
U | Unavailable | Proceed with authorization — no liability shift |
N | Authentication failed | Do not proceed; ask for another payment method |
R | Authentication rejected | Do not proceed; ask for another payment method |
C | Challenge required (step-up) | Wait for challenge completion before proceeding |
Postman collection
Download the official collection at github.com/tuna-software/postman. The 3DS folder contains all four integration mode examples with pre-configured environments and test variables.