Skip to main content

3DS Implementation & Testing (CIT with Redirection)

Customer Initiated Transactions (CIT) are 3DS transactions in which the customer is present during the transaction to complete any required external authorizations, such as a challenge.

This guide covers how to implement 3DS CIT with redirection, meaning the customer is redirected to the Basis Theory 3DS authentication page to complete the authentication process. If you are looking for a guide on how to implement 3DS CIT without redirection, embedding the authentication flow in your checkout page, please refer to the regular implementation guide here.

If you perform transactions without the customer present at checkout, these are classified as Merchant-Initiated Transactions (MIT). For guidance on implementing 3DS MIT, please refer to the implementation guide here.

Summary

This guide provides a comprehensive overview of determining when 3D Secure (3DS) authentication is required, properly implementing the authentication flow, handling customer redirection, and testing your implementation.

When is 3DS Required?

It is important to keep in mind every business has its own bespoke needs when it comes to risk, fraud, and compliance, and all of these variables impact its decision on how to best implement the 3DS authentication pattern for your business.

Triggering 3DS Considerations

Basis Theory simplifies this determination through the authentication field provided in the card token details object. When this value is sca_required, this suggests the underlying Issuer will require 3DS to be present during the transaction.

While this could likely be true, there are a few considerations and scenarios to consider as you decide how to best optimize for triggering 3DS and optimizing Payment Authorization success:

  • When a region always requires 3DS:
    • Consider always triggering 3DS when card.authentication is sca_required on your Token or Token Intent's card details object.
  • When a region does not always require 3DS:
    • Consider triggering the 3DS flow after a declined payment authorization to retry the transaction quickly while the customer is still engaged.
  • When receiving inconsistent payment authorization declines for Authentication data:
    • Consider triggering a frictionless only 3DS flow for these regions or BINs before Authorization. If a challenge is required, consider moving forward with your Authorization without the 3DS Authentication.
    • Consider triggering the 3DS flow after a declined authorization to retry the transaction quickly while the customer is still engaged.

Regulatory Context

Note: Always verify regulatory requirements specific to your region and confirm with your PSP to ensure compliance and avoid declined transactions.

Certain regions typically mandate 3DS authentication, notably:

  • European Economic Area (EEA)
  • United Kingdom (UK)
  • Other regions adopting Strong Customer Authentication (SCA): Australia, India, Brazil, and parts of Asia

Provisioning Resources

To successfully process 3DS authentications, you must first create two applications in the Basis Theory Portal: a Public Application and a Private Application. These applications will handle creating, authenticating, and retrieving 3DS sessions.

Public Application

The Public Application provides the public API key needed to create a 3DS session and construct the redirect URL that customers will be redirected to for 3DS authentication.

  • Permissions Required: 3ds:session:create

Click here to create the Public Application

Important: Save the generated API Key. You'll use it later in this guide.

Private Application

The Private Application is used by your backend system to retrieve 3DS sessions and challenge results.

  • Permissions Required: 3ds:session:read, 3ds:session:authenticate

Click here to create the Private Application

Important: Save the generated API Key. You'll use it later in this guide.

Creating a CIT 3DS Session

Unlike the regular CIT Implementation, the 3DS session with redirection is created from your backend instead of the client-side. It's important to note that the callback_urls parameter and authentication_request are required when creating the session if you are using redirection.

Here's the recommended minimum payload for creating a 3DS session with redirection in most scenarios:

{
token_id: "d65ead1a-84aa-45eb-96ba-f3e7e26087c0",
type: "customer",
device: "browser", // always use browser for 3DS with redirection
authentication_request: {
"authentication_category": "payment",
"authentication_type": "payment-transaction",
"challenge_preference": "no-challenge", // or challenge-requested if challenge is preferred (not guaranteed).
"card_brand": "Visa", // optional for co-badged cards
"merchant_info": {
"mid": "9876543210001",
"acquirer_bin": "000000999",
"name": "Example 3DS Merchant",
"country_code": "826",
"category_code": "5999",
"url": "https://example.com",
},
"requestor_info": { // if accepting American Express, Discover or Cartes Bancaires
"amex_requestor_type": "MER", // if American Express is accepted
"cb_siret_number": "78467169500087", // If Cartes Bancaires is accepted
},
"purchase_info": {
"amount": "80000",
"currency": "826",
"exponent": "2",
"date": "20250101141010",
"transaction_type": "purchase",
"installment_count": "5", // only for installment transactions
"recurring_expiration": "20250131", // only for recurring transactions
"recurring_frequency": "30", // only for recurring transactions
},
"cardholder_info": {
"name": "John Doe",
"email": "john@example.com",
}
},
callback_urls: {
success: "http://localhost:3000/success",
failure: "http://localhost:3000/failure"
}
}

And below is how you can use this object to create a 3DS session with the Basis Theory API and SDKs:

curl "https://api.basistheory.com/3ds/sessions" \
-H "BT-API-KEY: <PRIVATE_API_KEY>" \
-H "Content-Type: application/json" \
-X "POST" \
-d '{
"token_id": "d65ead1a-84aa-45eb-96ba-f3e7e26087c0",
"type": "customer",
"device": "browser",
"authentication_request": {
"authentication_category": "payment",
"authentication_type": "payment-transaction",
"challenge_preference": "no-challenge",
"card_brand": "Visa",
"merchant_info": {
"mid": "9876543210001",
"acquirer_bin": "000000999",
"name": "Example 3DS Merchant",
"category_code": "5999",
"country_code": "826",
"url": "https://example.com"
},
"requestor_info": {
"amex_requestor_type": "MER",
"cb_siret_number": "78467169500087"
},
"purchase_info": {
"amount": "80000",
"currency": "826",
"exponent": "2",
"date": "20240109141010",
"transaction_type": "purchase"
},
"cardholder_info": {
"name": "John Doe",
"email": "john@example.com"
}
},
"callback_urls": {
"success": "https://example.com/success",
"failure": "https://example.com/failure"
}
}'

3DS sessions that are not authenticated will expire according to the token or token-intent's designated expiration date. If no expiration date is set, the session expires after one hour. Once a session is successfully authenticated, it remains active indefinitely.

Populating the Authentication Request

The authentication_request parameter is a JSON object that contains the 3DS authentication request details. It is the accepted practice that the more information you provide to a 3DS session, the higher the likelihood of a frictionless authentication. Continue reading to learn more about each property in the Authentication Request object and how to best utilize them for your specific use case.

Authentication Category

For the authentication_category field, there are two authentication categories available - In most 3DS scenarios, you'll select the payment category, indicating that a current or future financial transaction (including $0 authentications) is intended.

Authentication CategoryDescription
paymentUtilized when a future financial transaction is intended (including $0 authentications).
non-paymentUtilized when the authentication is unrelated to an actual or anticipated charge. If you believe you need to utilize this category, please reach out to confirm your use-case.

Authentication Type

For the authentication_type field, there are three most common types available. The below table outlines the common scenarios for most merchants and platforms:

Authentication TypeDescription
payment-transactionUsed for a single exchange of goods (e.g. E-commerce checkout)
recurring-transactionUsed for on-going subscriptions where the billed amount is always the same. (e.g. Monthly Subscription)
installment-transactionUsed for breaking a single purchase into multiple installments. (e.g. Buy Now Pay Later)

If your use case does not align with these options, please contact us at support@basistheory.com to discuss what you should select.

Merchant Information

Merchant information allows the issuer and 3DS server to accurately identify your business during authentication. Correctly configuring these details is essential to prevent authentication failures.

Below is a detailed explanation of each merchant information field and guidelines for populating them.

You should have received these values from your Payment Service Provider (PSP) during the 3DS Setup process. If you have questions or haven't received the values for these fields, please contact your PSP and let them know that you need these details for each card network/brand you accept - a request template can be found here.

FieldDescription
midA unique identifier assigned by your PSP to identify your merchant account.
acquirer_binUnique numeric identifier assigned to the PSP by each card network/brand.
nameThe official business name associated with your PSP merchant account.
country_codeNumeric code representing merchant's country location (ISO 3166-1 standard).
category_codeA four-digit number assigned by your PSP indicating your type of business. Also known as MCC.
urlBusiness URL for the merchant.

Merchant information often varies depending on the card network or brand. You must implement logic within your application to dynamically select the appropriate values based on the card network or brand used for each transaction.

Merchant Information Example Object
"merchant_info": {
"mid": "9876543210001",
"acquirer_bin": "000000999",
"name": "Example 3DS Merchant",
"country_code": "826",
"category_code": "5999",
"url": "https://example.com",
}

Requestor Information for AMEX, Discover, Cartes Bancaires

American Express, Discover, and Cartes Bancaires (all supported by Basis Theory 3DS) require special 3DS Requestor information in addition to the standard Merchant Information.

If you accept payments from these networks, you should have received the necessary 3DS Requestor Information from your Payment Service Provider (PSP), as outlined in our 3DS Setup Guide.

If any details are missing or unclear, please contact your PSP directly, clearly communicating the specific data points required according to the setup guide - a request template can be found here.

Requestor Information for American Express (AMEX)
FieldDescription
amex_requestor_typeDefines the merchant type according to American Express requirements. For most cases, we recommend using MER, which represents a general merchant. If your business operates as an aggregator, an online travel agency, or you're unsure whether MER applies to your scenario, refer to the 3DS Setup Guide for alternative values and guidance.
Requestor Information for Cartes Bancaires
FieldDescription
cb_siret_number14-digit code that identifies a business establishment in France.
Requestor Information for Discover

Discover cards, predominantly issued by U.S. banks, rarely require Strong Customer Authentication (SCA).

If you need support for Discover 3DS authentication, please reach out via support@basistheory.com.

Requestor Information Example Object

To simplify implementations - these requestor fields may be included in every request regardless of the brand. Basis Theory automatically handles these values internally, using only those relevant to the card network involved in each transaction.

"requestor_info": {
"amex_requestor_type": "MER", // if American Express is accepted
"cb_siret_number": "78467169500087", // If Cartes Bancaires is accepted, replace with your real SIRET number
}

Purchase Information

It is essential to provide accurate details about the transaction to ensure successful authentication; if you believe you do not need to provide these values, please reach out.

The information below is recommended for all 3DS authentications regardless of the Authentication Type selected.

FieldDescription
amountThe purchase amount without any punctuation (i.e. 80000 for 800.00).
currencyThe purchase currency code in ISO 4127 standard.
exponentThe minor units of currency as in the ISO 4127 standard.
dateThe purchase date in UTC timezone and YYYYMMDDhhmmss format.
transaction_typeSpecifies the type of transaction being authenticated. For most use cases, we recommend using purchase. If your transaction falls under special scenarios, such as check acceptance or other uncommon types, refer to our API Reference for additional values and their descriptions.
Recurring Purchase

The following properties are required to be provided if your Authentication Type is set to recurring-transaction

Beyond the initial CIT authentication - Most recurring transactions or installments are exempt from 3DS authentication. However, the best practice is to verify with your PSP whether additional authentication exemptions or requirements apply to your recurring or installment transactions.

FieldDescription
recurring_expirationFinal recurring authorization date in YYYYMMDD format.
recurring_frequencyNumber of days between recurring charges.
Installment Purchase

The following property is required to be provided if your Authentication Type is set to installment-transaction

Beyond the initial CIT authentication - Most recurring transactions or installments are exempt from 3DS authentication. However, the best practice is to verify with your PSP whether additional authentication exemptions or requirements apply to your recurring or installment transactions.

FieldDescription
installment_countTotal number of installments for installment payments.
Purchase Information Example Object
"purchase_info": {
"amount": "80000",
"currency": "826",
"exponent": "2",
"date": "20250101141010"
"transaction_type": "purchase",

// only for installment transactions
"installment_count": "5",

// only for recurring transactions
"recurring_expiration": "20250131",
"recurring_frequency": "30",
}

Cardholder Information

Card networks strongly recommend including detailed cardholder information alongside transaction details to improve the likelihood of frictionless authentication.

As a general rule, providing more comprehensive information increases the effectiveness of the 3DS authentication process.

The fields below are, at a minimum, what most card networks require:

FieldDescription
nameThe full name of the cardholder full name.
emailThe email address on-file for the cardholder
Cardholder Information Example Object
"cardholder_info": {
"name": "John Doe",
"email": "john@example.com",
}

(Optional) Challenge Preference

For the challenge_preference field, the two most common values are available to instruct the issuer of the authentication preference. The table below outlines the common scenarios for most merchants and platforms:

Note: This preference is treated as a suggestion to the issuer and there is no guarantee it will be honored, as the final decision remains at the issuer's discretion.

Challenge PreferenceDescription
no-challengeUsed when preference for a frictionless authentication, to minimize friction by avoiding authentication challenges.
challenge-requestedUsed when explicitly requiring a challenge for the transaction - typically used if you suspect fraud.

To see more challenge preference options and related EMV codes, refer to our API Reference.

(Optional) Card Brand Selection

For co-badged cards (cards associated with multiple card networks), you can specify which card brand to use for authentication:

FieldDescription
card_brandThe specific card brand to use for authentication. Should be one of the brands returned in the additional_card_brands property when creating the session.

Selecting a specific brand allows you to route the authentication through the preferred network, which may be beneficial for:

  • Regional regulatory compliance (such as European PSD2 requirements)
  • Cost optimization by choosing the most economical network for a transaction
  • Customer preference for specific brand loyalty or rewards programs

If card_brand is not specified for a co-badged card, the default primary brand (returned in the card_brand property on session response) will be used.

Populating the Callback URLs

The callback_urls parameter is a required JSON object that specifies where to redirect customers after the 3DS authentication process completes. When creating a session with redirection, you must provide both a success and failure URL:

  • success: The URL where customers will be redirected after successful authentication
  • failure: The URL where customers will be redirected if authentication fails for any reason

These URLs should point to pages in your application that can appropriately handle the authentication outcome and continue the customer's journey.

{
"success": "https://example.com/success",
"failure": "https://example.com/failure"
}

Redirecting to the Authentication Page

After successfully creating a 3DS session (as shown in the previous section), you'll receive a response containing a redirect_url. This URL is used to redirect the customer to the Basis Theory 3DS authentication page where they will complete the authentication process.

https://api.basistheory.com/3ds/redirect/<SESSION_ID>?apiKey=<PUBLIC_API_KEY>

Where:

  • SESSION_ID is the unique identifier of the 3DS session you created
  • apiKey query parameter should be set to your PUBLIC_API_KEY

Implementation Approaches

You have two main options for handling the redirect:

For mobile devices or when you want a full-page experience:

// Redirect the current page to the 3DS authentication page
window.location.href = redirectUrl;

For desktop experiences where you want to keep the checkout page in the background:

// display configuration for the popup window
const popupConfig = {
width: 400,
height: 600,
scrollbars: 'yes',
resizable: 'yes',
toolbar: 'no',
menubar: 'no',
location: 'no',
directories: 'no',
status: 'no'
};

// calculate center position
const left = (screen.width - popupConfig.width) / 2;
const top = (screen.height - popupConfig.height) / 2;

const popupFeatures = `width=${popupConfig.width},height=${popupConfig.height},left=${left},top=${top},${Object.entries(popupConfig).filter(([key]) => key !== 'width' && key !== 'height').map(([key, value]) => `${key}=${value}`).join(',')}`;

try {
// open the popup window
const popup = window.open(redirectUrl, '3ds-authentication', popupFeatures);

// check if popup was blocked
if (!popup || popup.closed || typeof popup.closed === 'undefined') {
// fallback to full page redirect if popup is blocked
alert('Popup blocked. Redirecting to authentication page...');
window.location.href = redirectUrl;
return;
}

// optional: monitor popup status
const checkClosed = setInterval(() => {
if (popup.closed) {
clearInterval(checkClosed);
// Handle popup closure - you might want to check session status here
console.log('3DS popup was closed');
}
}, 1000);

} catch (error) {
console.error('Error opening popup:', error);
// Fallback to full page redirect
window.location.href = redirectUrl;
}

Authentication Flow

When customers are redirected to the Basis Theory 3DS authentication page:

  1. Initial Loading: The page loads and displays the authentication interface

3DS Redirect Loading State

  1. Authentication Process: Customers complete any required challenges (OTP, biometric, etc.)

3DS Redirect Authentication Page

  1. Result Processing: The authentication result is processed
  • Success:

3DS Redirect Success

  • Failure:

3DS Redirect Failure

  1. Callback Redirect: Customers are redirected to either your success or failure URL

Handling Authentication Completion

After the authentication process completes, customers will be redirected to one of the callback URLs you specified when creating the session:

  • Success URL: callback_urls.success - When authentication is successful
  • Failure URL: callback_urls.failure - When authentication fails

Best Practices

User Experience

  • Loading States: Show loading indicators while redirecting
  • Clear Communication: Inform users they'll be redirected for authentication
  • Fallback Options: Always provide fallback to full-page redirect if popups fail

Security Considerations

  • Popup Blockers: Consider popup blocker scenarios
  • URL Validation: Ensure redirect URLs are properly formatted
  • Timeout Handling: Implement timeouts for long-running authentications

Mobile Optimization

  • Responsive Design: Use full-page redirects on mobile devices
  • Deep Linking: Ensure proper handling of app-to-browser transitions

Error Handling

  • Network Issues: Handle network connectivity problems gracefully
  • Invalid Sessions: Provide clear error messages for invalid or expired sessions
  • Browser Compatibility: Test across different browsers and devices

Example: Complete Implementation

Here's a complete example that handles both popup and redirect scenarios:

function handleThreeDSRedirect(redirectUrl) {
// detect if user is on mobile device
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

if (isMobile) {
// use full page redirect for mobile
window.location.href = redirectUrl;
} else {
// try popup first for desktop
try {
const popup = window.open(
redirectUrl,
'3ds-authentication',
'width=400,height=600,scrollbars=yes,resizable=yes,toolbar=no,menubar=no,location=no,directories=no,status=no'
);

if (!popup || popup.closed || typeof popup.closed === 'undefined') {
// fallback to full page redirect
window.location.href = redirectUrl;
}
} catch (error) {
console.error('Error opening popup:', error);
window.location.href = redirectUrl;
}
}
}

// usage after session creation
handleThreeDSRedirect(sessionResponse.redirect_url);

Retrieving the 3DS Session

After the customer completes the authentication process and is redirected to one of your callback URLs, you need to retrieve the session to verify the authentication results and obtain the final authentication values needed for payment processing.

When to Retrieve the Session

You should retrieve the session:

  • After receiving a callback redirect - When the customer is redirected to your success or failure URL
  • Before processing payment - To get the authentication values (CAVV, ECI, etc.) for your payment processor
  • For verification - To confirm the authentication status and any challenge results

Retrieval Methods

You have two options for getting the session results:

Option 1: Direct API Retrieval

Make a GET request to retrieve the session immediately after receiving the callback redirect:

curl "https://api.basistheory.com/3ds/sessions/<SESSION_ID>" \
-H "BT-API-KEY: <PRIVATE_API_KEY>"

Option 2: Webhook Notifications

Alternatively, you can subscribe to webhook events to be notified when authentication completes:

The webhook events will not include the full authentication object, but you can use the session_id to retrieve the full session and get the authentication values. The main benefit of using webhooks is that the webhook events include the authentication_status value, which can be used to determine if the authentication was successful or not. This is useful if you want to handle different scenarios based on the authentication status.

Verifying the Authentication Results

The retrieved session contains an authentication object with everything you need to validate a 3DS transaction or identify why it failed. The code examples above show how to retrieve this data - now let's examine what to do with it.

See below a detailed table with descriptions for what each field means, and continue reading to understand different authentication scenarios that can happen with a 3DS transaction.

FieldDescription
session_idThe id for the authenticated 3DS session
threeds_versionThe 3DS version (i.e. 2.2.0) used in the transaction
token_idThe ID of the card token used in the 3DS transaction
token_intent_idThe ID of the card token intent used in the 3DS transaction
acs_transaction_idThe transaction ID from the 3DS Access Control Server (ACS)
ds_transaction_idThe transaction ID from the 3DS Directory Server (DS)
acs_reference_numberA unique identifier assigned to the DS by EMVCo
ds_reference_numberA unique identifier assigned to the ACS by EMVCo
authentication_valueThe 3DS cryptogram value used to authorize the transaction. Also know as CAVV, AAV, AEVV, etc.
authentication_statusThe outcome of the 3DS authentication. See Authentication Scenarios
authentication_status_codeEMVCo character code for the authentication status
authentication_status_reasonAdditional information about the authentication status if necessary. See Failed Authentication. Not provided on frictionless authentication
authentication_status_reason_codeEMVCo numeric code for the authentication status reason.
directory_status_codeEMVCo character code for the directory status
eciElectronic Commerce Indicator (ECI)
acs_challenge_mandatedIndicates whether regional mandates (e.g., PSD2) require a challenge to be performed
authentication_challenge_typeThe type of challenge authentication used (if challenge)
acs_challenge_urlThe URL to be used for the challenge
challenge_preferenceThe selected Challenge Preference during authentication
challenge_preference_codeEMVCo numeric code for the selected challenge preference
challenge_attemptsThe number of challenges attempted by the cardholder. Not provided on frictionless authentication
challenge_cancel_reasonThe reason why a challenge was cancelled. Not provided on frictionless authentication
challenge_cancel_reason_codeEMVCo numeric code for the challenge cancel reason. Not provided on frictionless authentication
cardholder_infoUnspecified information from the issuer to be displayed to the cardholder
whitelist_statusIndicates if the cardholder whitelisted the merchant
whitelist_status_sourceIdentifies the system that set the whitelist value
message_extensionsArray of Message Extensions - Data necessary to support requirements not defined in the standard 3DS format

Authentication Scenarios

Below are how to handle the scenarios that could be returned from the Authentication step. Generally, this will fall into he following scenarios:

Authentication ScenariosDirectory Status CodeDescription
FrictionlessY, AThe authentication was approved by the issuer and the transaction may proceed.
ChallengeCThe issuer is requesting additional authentication before allowing the transaction to proceed.
Decoupled ChallengeDThe issuer requires additional authentication to be performed outside of the transaction scope.
3DS FailedN, U, RThe 3DS authentication was not approved. Reason is provided in authentication_status_reason property.
Frictionless Authentication

If the authentication_status indicates success, and the directory_status_code indicates Y or A, your authentication has been approved, and the response includes the authentication values needed to send to your Processor.

Note: The attempted status also produces a frictionless authentication. However, in this case, it indicates the ACS (Access Control Server) encountered an issue authenticating the transaction. From the merchant's perspective, it works like a success (no further authentication steps are required), although liability considerations may differ.

Challenge Authentication

If the directory_status_code indicates the code C, the cardholder completed an additional verification step inside the Basis Theory 3DS Authentication page—a "Challenge"—before the 3DS authentication could be finalized and the final authentication value (CAVV) provided. Alternatively, you can use our Webhooks solution. Subscribing a webhook to the 3ds.session.challenge-completed event will trigger when a challenge completion has finished and contain the id to enable Getting a Challenge Result.

Challenges can vary significantly, often involving methods such as entering a one-time password (OTP) or authorizing the transaction via a banking app. The presentation and completion method of the challenge are determined entirely by the issuer, and the merchant has no control over this process.

Getting a Challenge Result

Once a challenge is completed, you must retrieve the result directly from the API. This step is essential to determining the challenge's outcome (success or failure) and obtaining the necessary authentication values (e.g., CAVV, ECI) for successfully authenticated transactions.

curl "https://api.basistheory.com/3ds/sessions/<SESSION_ID>/challenge-result" \
-H "BT-API-KEY: <PRIVATE_API_KEY>"
Decoupled Challenge Authentication

Decoupled Challenge Authentication is a 3DS method that separates cardholder authentication from the payment flow, allowing the issuer to handle authentication without direct cardholder interaction at the time of the transaction. If the directory_status_code indicates the code D, then that indicates a Decoupled Challenge Authentication.

This approach is more common in Merchant-Initiated Transactions (MIT) but possible in cases where the cardholder's device cannot support a typical challenge flow during a CIT.

Since this authentication occurs outside the immediate transaction flow, you must subscribe to the 3ds.session.decoupled-challenge-notification event via Webhooks to confirm when the authentication is complete.

Failed Authentication

A 3DS authentication may fail for various reasons, ranging from technical issues to rejections triggered by fraud or risk concerns. When you encounter a failed, unavailable, or rejected authentication_status, refer to the authentication_status_reason property to understand why the authentication did not succeed.

Depending on the reason, you can either:

  • Retry the 3DS authentication using the same information.
  • Adjust the authentication request (e.g., providing more details) before retrying.

The following table outlines possible authentication_status_reason values and recommended actions.

Authentication Status ReasonRecommended Action
low-confidence
medium-confidence
high-confidence
very-high-confidence
authentication-attempted-but-not-performed
identity-check-insights
The authentication was successful even though it failed, use authentication results returned with payment.
invalid-transaction
transaction-not-permitted
cardholder-not-enrolled
non-payment-transaction-not-support
3ri-not-supported
vmid-not-eligible-for-requested-program
protocol-version-not-supported-by-acs
Attempt payment without 3DS authentication.
card-authentication-failed
too-many-authentication-attempts
card-expired
invalid-card-number
no-card-record
security-failure
stolen-card
suspected-fraud
Inform consumer to use a different card or double-check details.
unknown-device
unsupported-device
Inform consumer to use a different device.
timeout-at-acs
max-challenges-exceeded
acs-technical-issue
decoupled-authentication-required
decoupled-authentication-timeout
insufficient-decoupled-authentication-time
error-connecting-to-acs
acs-timed-out
invalid-response-from-acs
system-error-response-from-acs
internal-error-while-generating-cavv
device-3ri-not-routed-to-smart-authentication-stand-in
transaction-excluded-from-attempts-processing
Retry authentication.

Refer to our API documentation for details on what each reason code means specifically.

Testing Basis Theory 3DS

Basis Theory Test Tenants automatically connect to the sandbox environment for testing your 3DS implementation. This environment allows you to simulate the 3DS authentication flow without real-world impacts safely. To utilize 3DS in your Test Tenant, ensure 3DS has been enabled in your Tenant Quotas.

To guarantee a predictable and deterministic pattern for both automated and manual testing, a set of Test Cards exists to simulate different Authentication outcomes, helping validate various scenarios effectively.

Test Cards

Below is a list of Luhn-valid test cards that can be used to simulate different authentication scenarios in the sandbox environment. These cards are not real and will not work for testing in production environments.

Card NumberCard BrandTesting Scenario
5204247750001471MASTERCARDSuccessful Frictionless Authentication
6011601160116011DISCOVERSuccessful Frictionless Authentication
340000000004001AMEXSuccessful Frictionless Authentication
4000020000000000VISASuccessful Challenge Authentication
370000000000002AMEXSuccessful Challenge Authentication
3566002020360505JCBSuccessful Challenge Authentication
3566006663297692JCBSuccessful Challenge Authentication
4005562231212123VISASuccessful Challenge Authentication - Method not Required
4761369980320253VISASuccessful Mandated Challenge Authentication
5200000000001104MASTERCARDSuccessful Mandated Challenge Authentication
4000000000000341VISASuccessful Out-of-Band Challenge Authentication
4005571701111111VISAAttempted Challenge Authentication
4111111111111111VISAAuthentication Attempted
5424180011113336MASTERCARDAuthentication Attempted
4264281511112228VISAAuthentication Failed
5424180000000171MASTERCARDAuthentication Failed
5405001111111165MASTERCARDAuthentication Unavailable
5405001111111116MASTERCARDAuthentication Rejected
4055011111111111VISAFailed Challenge Authentication
5427660064241339MASTERCARDFailed Challenge Authentication
6011361011110004DISCOVERFailed Out of Band Challenge Authentication
6011361000008888DISCOVERUnavailable Challenge Authentication
6011361000001115DISCOVERRejected Challenge Authentication
4264281500003339VISA3DS Directory Server Error
5424180011110001MASTERCARD3DS Directory Server Error
4264281500001119VISAInternal 3DS Server Error
4150580996517927VISA, CARTES BANCAIRESCo-Badged Card - Successful Challenge Authentication
4150580996517927MASTERCARD, CARTES BANCAIRESCo-Badged Card - Successful Challenge Authentication

Error Handling

Proper error handling is crucial for delivering a smooth user experience when implementing 3DS authentication. There are two primary categories of errors you'll encounter:

Handling 3DS Service Errors

3DS Service Errors occur when issues arise during the external 3DS authentication process. These errors are returned with a 424 HTTP status code, providing detailed information on the failure:

{
"error": {
"title": "3DS Service Error",
"detail": "The 3DS service returned an error. See the 'error' field for more details.",
"status": 424,
"error": {
"service_status": "403",
"session_id": "c0c22fcd-d42c-497e-a9a6-2eacd31770d7",
"error_source": "3DS Server",
"message": "Access denied by issuer. See 'details' for additional detail.",
"detail": "The merchant_info.acquirer_bin is not recognized by the issuer."
}
}
}

The error object will contain all the necessary details on what the error was and how to handle it. Below are some suggestions on how to handle common errors based on the received error.service_status code.

Service StatusError ScenarioPossible Actions
400Bad RequestCheck the request payload and ensure it's correct. Details are include in the message and detail fields.
401, 403Access DeniedCheck your merchant information (MID, Acquirer BIN, etc.) and ensure it's correct for the card network you're using.
404Not FoundCheck if the session ID is correct and that the session exists in the tenant.
5XXInternal Service ErrorsCheck the error message and if applicable, retry the authentication.

If you have questions about specific error codes or how to handle them, please reach out to our support team at support@basistheory.com.

You can find below examples of how to handle 3DS Service Errors using the backend SDKs.

import { BasisTheoryClient, BasisTheoryError } from "@basis-theory/node-sdk";

try {
const authentication = await bt.threeds.sessions.authenticate(sessionId, {
authenticationCategory: "payment",
authenticationType: "payment-transaction",
// ... other properties
});

// ... handle successful authentication

} catch (error) {
if (error instanceof BasisTheoryError) {
const statusCode = error.statusCode;

if (statusCode === 424) {
// handle specific 3DS service error
const serviceError = JSON.parse(error.body).error;

console.error("Error Message:", serviceError.message);
console.error("Details:", serviceError.detail);
console.error("Service Status:", serviceError.service_status);
console.error("Error Source:", serviceError.error_source);
console.error("Session ID:", serviceError.session_id);
} else {
// handle other Basis Theory API errors
console.error("Basis Theory API Error:", error.message);
}
} else {
// handle unknown errors
console.error("Unexpected Error:", error);
}
}

3DS Redirection Implementation FAQs

What is a Basis Theory 3DS Session?

A Basis Theory 3DS Session represents the lifecycle of a 3DS authentication process.

It stores transaction details and dynamically captures data as each step of the authentication flow is completed, providing a complete record of the transaction's 3DS authentication journey.

What is the difference between a 3DS Session with or without redirection?

A 3DS Session with redirection is created from the backend by passing the authentication_request upfront and including callback_urls. The device data collection, authentication and challenge handling is all performed by Basis Theory inside the provided redirect_url.

A 3DS Session without redirection is created from the frontend using the provided Basis Theory SDKs. The authentication and challenge handling is done by the customer, using the SDKs, providing a more customizable experience.

Is it possible to change the styling or add my company logo to the 3DS redirection page?

At the moment, you cannot change the styling or add your company logo to the 3DS redirection page.

Reach out to our support team if you wish to explore this possibility in the future.

How long is a 3DS Session kept in the Basis Theory vault?

When a 3DS session is created, its expiration date inherits that of the token or token-intent used. The session defaults to a one-hour expiration if no expiration date is present.

However, once the session is authenticated, it no longer expires and remains stored indefinitely—provided your tenant remains active.

How can I retrieve a 3DS Session to see its details?

Use the Get Session endpoint, ensuring you include a private application key with the 3ds:session:read permission.

Are there limits on the number of 3DS sessions I can create?

No. There are currently no restrictions on how many 3DS sessions you can create for the same token, token-intent or in general.

You're free to create as many as you need for testing or operational purposes.

What authentication_category should I use in most authentication scenarios?

In the majority of cases, including both current or future charges, set the authentication_category to payment.

What authentication_type should I use in most authentication scenarios?

For most single-purchase or one-time payment scenarios, use the purchase-transaction.

For recurring transactions where the same amount is charged each month, use recurring-transaction.

For installment transactions where a product is broken into multiple payments, use installment-transaction

What settings do I use if I only do a $0 Authorization?

Yes, when doing pre-authorizations, that signifies the intent to charge - you should use payment as the authentication_category and payment-transaction as the authentication_type.

How do I find my Merchant Information?

Your Payment Service Provider (PSP) is responsible for providing these details.

Refer to our Setup Guide for specific instructions on communicating your requirements and ensuring your PSP gives you the necessary merchant data.

Can I store my Merchant Information with Basis Theory so I don't have to include it in every authentication request?

At the moment, you must provide this information with each request. However, Basis Theory is actively developing a solution that will allow you to store these values and automatically populate them on future 3DS requests.

I support AMEX, what value should I use as the requestor_info.amex_requestor_type?

If you are a merchant or are processing for a Merchant, you will usually set requestor_info.amex_requestor_type to MER.

If your organization fits a different category (e.g., aggregator, online travel agency), refer to the available AMEX requestor types in our Setup Guide or consult your PSP.

How does a recurring or installment transaction work? Do I need to repeat 3DS authentication for each additional charge?

When processing recurring or installment transactions using 3DS, we recommend performing an initial Cardholder-Initiated Transaction (CIT) authentication, ensuring you include the appropriate recurring or installment details.

Typically, subsequent recurring or installment payments do not require additional 3DS authentications. However, it's best practice to confirm with your PSP if they have additional requirements or guidelines.

If your PSP indicates that additional authentications are needed for subsequent payments, you can reuse the authentication value from the initial CIT authentication or perform a new 3DS authentication while including the prior authentication information.

This approach helps ensure frictionless authentications for ongoing payments.

What information about the cardholder do I need to provide?

Most card networks require, at a minimum, the cardholder's name and email address.

Providing additional details (such as billing address or phone number) can help improve authentication success rates, especially if you experience lower-than-expected approval rates.

Refer to the Taking 3DS Live Guide for further recommendations.

Will my set Challenge Preference always be respected by the issuer?

No. The challenge_preference you set is only a suggestion. The issuer decides whether to prompt a challenge based on its risk assessment and compliance requirements.

What is a frictionless 3DS authentication?

A frictionless 3DS authentication is a successful authentication where no challenge was required.

How can I verify a non-frictionless challenge was completed?

With the redirection approach, the customer will be redirected to your success or failure callback URL after completing the challenge. You can also use the 3ds.session.challenge-completed webhook to be notified when the challenge is completed.

How do I handle co-badged cards in 3DS authentication?

When creating a 3DS session for a co-badged card (a card associated with multiple networks), the response will include an additionalCardBrands array listing all brands the card supports.

During authentication, you can specify which brand to use by including the card_brand parameter with the desired brand name. This allows you to route the authentication through your preferred network based on considerations like regional regulations, costs, or customer preferences.

If no card_brand is specified, the authentication will default to the primary card brand (the first one in the additionalCardBrands array).

Is it possible to detect when a user cancels a challenge in real time?

No. To confirm that a user has canceled a challenge, you must retrieve the challenge result via the Get a Challenge Result endpoint.

The response will include a challenge_cancel_reason, indicating that the user explicitly canceled the challenge.

How can I retrieve the authentication values of a completed challenge?

You should use the Get Challenge Result endpoint to get the results of a challenge.

Is it possible for CITs to have decoupled challenges?

Yes. Although decoupled challenges are more commonly used in Merchant-Initiated Transactions (MITs), they can occur in Customer-Initiated Transactions (CITs) as well—particularly if the cardholder's device doesn't support the standard challenge flow.

Is it possible to style the way a challenge window looks?

The issuer or acquirer fully controls the design and layout of the challenge window (e.g., fonts and colors).

With the redirection approach, the challenge is presented directly on the Basis Theory authentication page, so styling customization is limited. However, you can customize the popup window size and placement if you're using the popup implementation approach.

Does Basis Theory provide a way to test a 3DS implementation?

Yes, 3DS authentications from a Test Tenant will use our 3DS Sandbox environment. For more details, refer to the Testing session in this guide.

Does Basis Theory provide test cards for use in the testing environment?

Yes, refer to the Test Cards session in this guide.

Does Basis Theory provide test cards for use in a production environment?

No. You must use your real cards or request production-ready test cards from your PSP.

Basis Theory does not support test scenarios in production; any card used in a production tenant will undergo a live 3DS authentication with real data.

Can I test a 3DS implementation End-to-End(E2E) between Basis Theory and my PSP?

There are a few options for how to test implementations in Test and Production Tenants.

For Test Tenants: The nature of standalone 3DS typically prevents fully end-to-end payment tests in a sandbox environment because Basis Theory and the PSP each have separate test data sets.

  • To test 3DS scenarios, Use Basis Theory's 3DS Test Cards.
  • To test the PSP authorization with 3DS data: Follow your PSP's testing guidelines. This often involves using their specific test cards and dummy 3DS values.

For Production Tenants: You can utilize your real-life cards to test the implementation fully end to end with Basis Theory and all of your PSPs.