3D Secure (3DS) Payment Flow
This guide explains how to integrate the 3D Secure (3DS) redirect-based authentication flow using Ecart Pay. The goal is to authenticate the cardholder (when required) and then process the payment, returning the user to your application via a controlled redirect.
Test Cards (3D Secure)
Use the following test cards to validate the 3D Secure (3DS) flow in your sandbox environment. These cards simulate different 3DS outcomes (frictionless and step-up), including successful and unsuccessful authentication scenarios.
Note: These cards are for testing purposes only and must not be used in production.
Test Card List
| Card Number | Brand | Exp. Month | Exp. Year | 3DS Enabled | Expected Payment Status | Scenario Description |
|---|---|---|---|---|---|---|
4000 0000 0000 2701 | Visa | 01 | 2050 | ✅ | paid | Successful frictionless authentication |
4000 0000 0000 2925 | Visa | 12 | 2050 | ✅ | paid | Unsuccessful frictionless authentication |
4000 0000 0000 2503 | Visa | 11 | 2050 | ✅ | paid | Successful step-up authentication |
4000 0000 0000 2370 | Visa | 11 | 2050 | ✅ | paid | Unsuccessful step-up authentication |
Overview
The 3DS flow in Ecart Pay works like this:
- Create a payment order
- Obtain a card token (permanent or single-use)
- Create the 3DS enrollment
- Redirect the user to Ecart Pay for authentication
- Ecart Pay runs 3DS and attempts payment processing
- Ecart Pay redirects the user back to your
redirect_url - Confirm the final result by querying the order status
Flow Summary
- Create a payment order.
- Obtain a card token (permanent or single-use).
- Create a 3DS enrollment using
POST /api/three-d-secure. - Redirect the user to the
urlreturned in the response. - Ecart Pay runs the 3DS authentication and processes the payment.
- Ecart Pay redirects the user back to your
redirect_urlincluding result parameters. - Query the order status using
GET /api/orders/:id. - Review 3DS indicators and activity logs in the order
activityattribute.
Prerequisites
Before starting the 3DS flow, you must have:
1) Payment Order (order_id)
order_id)A payment order must be created first, since the order ID is required to create the 3DS record.
2) Card Token (token)
token)You must also provide a card token, which can be either:
- Permanent token
- Single-use token
1. Create a 3D Secure Enrollment
Once you have your order_id and token, start the 3DS process by creating a 3D Secure record.
Endpoint
POST /api/three-d-secure
Important: redirect_url
redirect_urlMake sure you send a redirect_url, since Ecart Pay will redirect the user back to that URL once the 3DS flow is completed.
- For web apps, use a standard HTTPS URL.
- For mobile apps, this can be a deeplink.
Required Request Body Fields
You must send:
order_id(string) — the payment order IDtoken(string) — the card token (permanent or single-use)redirect_url(string) — the URL where the user should be returned after the 3DS flow
{
"order_id": "69581fcb2bdfc3343fb983c9",
"token": "6954201a0deca359dec01434",
"redirect_url": "https://example.com/three-d-secure/process-payment"
}2. Redirect the User to the Enrollment URL
The enrollment response includes a url attribute.
✅ Your integration must redirect the user to that URL to start the 3DS authentication flow.
{
"account_id": "5fab3b20b40b0a613e1b6f15",
"order_id": "69581fcb2bdfc3343fb983c9",
"status": "created",
"action": "enrollment",
"url": "https://checkoutdev.ecartpay.com/three-d-secure?id=695d34b6d8740550a67373fb",
"reference_id": "cba34245-3939-4302-8bbc-ea782f9f5f7c",
"auth_info": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"device_data_collection_url": "https://centinelapistag.cardinalcommerce.com/V1/Cruise/Collect",
"token": "AxizbwSToC4ALZA3aKlGACcBT36oZRDoAu7QyaSZejF6eAuAgAAATgns"
},
"redirect_url": "https://example.com/three-d-secure/process-payment",
"id": "695d34b6d8740550a67373fb"
}What to do with the response
Store these values for traceability and troubleshooting:
id(3DS id)reference_idorder_id
Then redirect the user to:
url
3. Authentication and Payment Processing (Handled by Ecart Pay)
After the user is redirected:
- Ecart Pay runs the 3DS authentication flow
- Ecart Pay attempts payment processing
- Regardless of success or failure, Ecart Pay redirects the user back to your
redirect_url
✅ You do not need to take any action during this phase besides waiting for the final redirect.
4. Final Redirect Back to Your redirect_url
redirect_urlOnce the flow ends, Ecart Pay redirects the user back to your redirect_url and includes query parameters.
Returned Parameters
order_id— the order IDthreeds_status— the 3DS flow result statuserror(optional) — included when authentication or payment fails
Important: Even if
threeds_statusindicates success, you must always validate the payment by checking the order status.
5. Confirm the Payment Status (Required)
In your redirect handler endpoint (your redirect_url), you must query the order status to confirm whether the payment was actually completed.
Endpoint
GET /api/orders/:id
Expected Result
- If
statusispaid→ ✅ payment successful - If the status is anything else → ❌ payment not completed or failed
✅ This is the source of truth for your UI and business logic.
6. 3DS Activity and Indicators
To review 3DS indicators, authentication details, and the payment attempt history, check the activity attribute in the order response.
✅ The activity field contains the relevant 3DS information and the transaction timeline.
Implementation Recommendations
- Always use the order status as the source of truth. Do not assume success based only on
threeds_status. - In your
redirect_urlhandler, always query the order and display the final result to the user. - Store
reference_idand/or the returned 3DSidfor internal traceability and correlation across logs. - Treat your
redirect_urlas a public endpoint: validate parameters, log events, and avoid exposing sensitive logic on the client side.
Notes
- The final redirect may occur even when authentication fails or the bank declines the payment.
- The only way to confirm that funds were captured is by querying the order and verifying it is in
paidstatus. - If the user closes the browser before returning, you can still query the order status from your backend.
Updated 28 days ago