3D Secure 2 (3DS2) guide
3D Secure 2 (3DS2) is a cardholder authentication protocol used for card-not-present payments. It adds an authentication step between payment submission and issuer authorisation, which reduces fraud and, for authenticated transactions, shifts chargeback liability to the issuer.
This page is the canonical reference for how 3DS2 works with Payments AI: when it applies, how to maximise the rate of frictionless flows, the step-by-step challenge flow, and how the hosted payment form handles 3DS automatically for subscriptions.
When 3DS triggers
3DS is disabled by default for all gateway connections. Activation requirements depend on your legal corporate location and the markets where you sell:
- EU/UK merchants: 3DS is mandatory under PSD2 Strong Customer Authentication (SCA) regulations for transactions involving regional cardholders.
- Japan merchants: 3DS is mandatory for transactions with cards issued in Japan.
- US and other markets: 3DS is optional. Activating it shifts chargeback liability to the issuer for authenticated transactions and is recommended where fraud rates are elevated.
For activation instructions and local compliance rules, see the Business Decision Matrix.
Frictionless vs challenge flow
When 3DS is active, every eligible transaction goes through an initial check. The cardholder's issuing bank decides which flow applies based on the transaction data profile:
- Frictionless flow: The bank reviews the risk signals silently and authenticates the customer without displaying extra security prompts. The checkout experience remains identical to a standard card payment.
- Challenge flow: The bank requires active confirmation — such as a one-time code, biometric verification, or a banking-app authorisation. The customer is redirected to the bank's security page and returned to your store after completing the challenge.
Providing a complete and consistent dataset increases the likelihood of a frictionless outcome. See How to Increase Approval Rate for the broader approval-rate strategy; the next section focuses specifically on the 3DS-relevant fields.
Maximising the frictionless rate
Banks grant frictionless approvals when they trust the incoming transaction metadata. Payments AI automatically forwards your checkout payload to the issuer during validation, so completeness on your side directly affects the outcome.
The most critical fields live inside riskMetadata on the transaction request:
| Field | Why it matters |
|---|---|
riskMetadata.ipAddress | Customer IP at checkout. An IP whose geolocation is consistent with the billing country is a positive risk signal. |
riskMetadata.fingerprint | Device fingerprint generated client-side. Keeping it stable across sessions for the same returning customer helps the bank recognise legitimate traffic. |
riskMetadata.browserData.colorDepth | Screen colour depth in bits. Required for 3DS2. |
riskMetadata.browserData.isJavaEnabled | Whether Java is enabled in the browser. Required for 3DS2. |
riskMetadata.browserData.language | Browser language (for example en-US). Required for 3DS2. |
riskMetadata.browserData.screenWidth | Screen width in pixels. Required for 3DS2. |
riskMetadata.browserData.screenHeight | Screen height in pixels. Required for 3DS2. |
riskMetadata.browserData.timeZoneOffset | UTC offset in minutes (for example 300 for UTC-5). Required for 3DS2. |
riskMetadata.browserData.isAdBlockEnabled | Whether an ad blocker is active in the browser. |
| Returning-customer history | Customers with a successful prior history on the issuer side are more likely to be authenticated frictionlessly. |
Challenge flow: Step-by-step
When the issuing bank requires a challenge, your application must process through six stages.
1. Create the transaction with a redirectUrl
When constructing your initial transaction request, include a redirectUrl so the customer has a defined return path after authenticating:
curl --location 'https://api.payments.ai/v1/public-api/organizations/:organizationId/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: ApiKey <keyValue>' \
--data '{
"customerId": "{{customerId}}",
"currency": "USD",
"amount": 99,
"type": "sale",
"paymentInstruction": {
"paymentInstrumentId": "{{paymentInstrumentId}}"
},
"redirectUrl": "https://yoursite.com/{id}/{result}"
}'
The {id} and {result} placeholders are automatically populated by Payments AI when routing the customer's browser back to your site.
2. Check the response for status: waiting
If the bank requires a challenge, the API response returns status: "waiting" alongside an approvalLink:
{
"data": {
"id": "txn_abc123",
"status": "waiting",
"result": "unknown",
"approvalLink": "https://3ds.example/..."
}
}
If the transaction qualifies for a frictionless flow, it skips this phase entirely and completes immediately with status: "completed" and result: "approved" or "declined" — no further action is required.
3. Redirect the customer to approvalLink
When status is waiting, redirect the customer's browser to the URL in approvalLink. This sends them to the bank's secure authentication screen.
4. Customer completes authentication on the bank's page
The customer enters the one-time code, completes the biometric check, or confirms in their banking app. Payments AI does not participate in this exchange; it occurs directly between the customer and their issuer.
5. Payments AI redirects the customer back to redirectUrl
After authentication, Payments AI redirects the customer to the redirectUrl you provided, substituting {id} and {result} with the actual values:
https://yoursite.com/txn_abc123/approved
https://yoursite.com/txn_abc123/declined
https://yoursite.com/txn_abc123/abandoned
6. Read the {result} and confirm via API or webhook
The {result} parameter communicates the outcome of the authenticated transaction:
| Result | Meaning |
|---|---|
approved | The bank authorised the payment. |
declined | The bank declined after authentication. |
abandoned | The customer exited the authentication interface without completing it. |
canceled | The transaction was voided. |
unknown | Final result not yet determined; poll the transaction or wait for the webhook. |
For the authoritative final state, retrieve the transaction by ID or handle the incoming webhook. The transaction statuses relevant to 3DS are:
| Status | Meaning |
|---|---|
waiting | 3DS authentication required — redirect the customer to approvalLink. |
offsite | The transaction is actively processing on the bank's validation page. |
completed | Transaction finished; check result for the outcome. |
timeout | Authentication or processing timed out on the issuer side. |
Hosted payment form (subscriptions)
For subscription flows, customers typically complete the first payment on the hosted payment form at secure-payments.app. Payments AI manages the entire 3DS orchestration natively on this form, removing the need for custom frontend challenge logic on your side.
The hosted form handles:
- Collecting card details (the data never reaches your server).
- Triggering 3DS authentication when the bank requests a challenge.
- Setting up the recurring payment token once the first payment succeeds.
- Redirecting the customer back to your
redirectUrlwith the result.
See Hosted Payment Form for the full description and Create a Subscription for the end-to-end subscription flow that uses it.
Webhook notifications
When a transaction fails 3DS authentication — whether the issuer declines, the customer abandons, or a timeout occurs — Payments AI dispatches the transaction-declined webhook. See Transaction Declined webhook. For the full event payload structure, see the Webhooks schemas.
Testing
Payments AI provides dedicated test card numbers for every 3DS scenario, including frictionless successes, forced challenges, frictionless declines, and non-3DS cards. Run these validation checks on the staging environment before switching to production credentials.
See Test Cards for the full list.