> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thedecard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Handling 3DS Challenges

> All fields of the AUTHORISATION_3DS_CHALLENGE event with OOB and OTP_DELEGATE payload examples; the division of work across the three authentication modes; OOB results return via the authenticate endpoint, idempotent on repeat.

## 📄 Guide

When an online purchase triggers 3DS authentication, DCS forwards the challenge to the partner: the webhook `AUTHORISATION_3DS_CHALLENGE` is pushed, and you take part in verification or code delivery per the mode configured at onboarding (the mode is set per card BIN range on the issuing side). This page covers the challenge event's full field set with both payload examples, what each mode asks of you, and how to call the one and only result-return endpoint for OOB.

## AUTHORISATION\_3DS\_CHALLENGE: the challenge event

The event's `data` fields:

| Field                                                         | Description                                                                                                |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `challengeId`                                                 | The challenge ID; for OOB, pass it verbatim to the authenticate endpoint                                   |
| `status`                                                      | Challenge state (`INIT` when delivered)                                                                    |
| `cardId` / `organizationId`                                   | The card that triggered the challenge and its company                                                      |
| `expiryTime`                                                  | Challenge expiry, format `yyyy-MM-dd'T'HH:mm:ssXXX`                                                        |
| `currency` / `amount`                                         | Transaction currency (numeric ISO 4217 code, e.g. `840`) and amount                                        |
| `merchantId` / `merchantName` / `merchantCountryCode` / `mcc` | Merchant details                                                                                           |
| `challengeFlowType`                                           | Challenge mode: `OOB` / `OTP_DELEGATE`                                                                     |
| `challengeMethodType`                                         | Challenge method (e.g. `DELEGATE_SCA_V1` / `SMS_OTP`)                                                      |
| `encryptedOtpPasscode`                                        | Encrypted one-time code (AES-GCM, Base64), **OTP\_DELEGATE only**                                          |
| `phoneNumber` / `email`                                       | Cardholder phone / email ciphertexts (AES-GCM, Base64), OTP\_DELEGATE only; the unconfigured one is `null` |
| `iv`                                                          | AES-GCM initialization vector (Base64), shared by all ciphertext fields in the event                       |

**OOB challenge payload example** (basic transaction details only — verification happens in your app):

```json theme={null}
{
  "challengeId": "5211234567890123456",
  "status": "INIT",
  "cardId": "5136759791164443137",
  "organizationId": "1276574398205403138",
  "expiryTime": "2026-08-13T19:31:30+08:00",
  "currency": "840",
  "amount": 129.99,
  "merchantId": "MCT00001",
  "merchantName": "EXAMPLE ONLINE STORE",
  "merchantCountryCode": "IE",
  "mcc": "5732",
  "challengeFlowType": "OOB",
  "challengeMethodType": "DELEGATE_SCA_V1"
}
```

**OTP\_DELEGATE challenge payload example** (additionally carries the code and delivery-channel ciphertexts):

```json theme={null}
{
  "challengeId": "5211234567890123457",
  "status": "INIT",
  "cardId": "5136759791164443137",
  "organizationId": "1276574398205403138",
  "expiryTime": "2026-08-13T19:31:30+08:00",
  "currency": "344",
  "amount": 500.00,
  "merchantId": "MCT00002",
  "merchantName": "EXAMPLE TRAVEL",
  "merchantCountryCode": "HK",
  "mcc": "4722",
  "challengeFlowType": "OTP_DELEGATE",
  "challengeMethodType": "SMS_OTP",
  "encryptedOtpPasscode": "kX9… (AES-GCM ciphertext, Base64)",
  "phoneNumber": "aB3… (AES-GCM ciphertext, Base64)",
  "email": null,
  "iv": "R4nd0mIVBase64=="
}
```

## Division of work across the three modes

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/corp-3ds-challenges-light.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=ba95e30242ed8989b1e0a8068287340a" alt="Division of work across the three 3DS challenge modes" width="595" height="786" data-path="imgs/en/diagrams/corp-3ds-challenges-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/dcs-0bf7a937/oUoeUKtwWWK2o-Li/imgs/en/diagrams/corp-3ds-challenges-dark.svg?fit=max&auto=format&n=oUoeUKtwWWK2o-Li&q=85&s=fd19f0573eab1e57f61ca9adf1ac558e" alt="Division of work across the three 3DS challenge modes" width="595" height="786" data-path="imgs/en/diagrams/corp-3ds-challenges-dark.svg" />
</Frame>

On receiving a challenge event, handle it per the mode configured at onboarding:

| Mode           | Challenge delivery                                                                   | Who handles it                                                                                                                                                |
| -------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer OTP     | DCS sends the code to the cardholder directly (email / SMS)                          | The whole challenge loop closes inside DCS — the partner is not involved and receives no challenge event                                                      |
| `OTP_DELEGATE` | DCS pushes a webhook to the partner carrying the code plus email / phone ciphertexts | The partner decrypts and delivers the code to the cardholder through its own channel; the cardholder enters it on the challenge page — **no result callback** |
| `OOB`          | DCS pushes a webhook to the partner carrying the basic transaction details           | The partner notifies the cardholder's app → the cardholder verifies in-app → the partner calls the authenticate endpoint to return the result to DCS          |

<Warning>
  **Challenges are valid for about 300 seconds** (the event's `expiryTime` is authoritative) and time out as rejected. The result-confirmation endpoint applies to OOB mode only.
</Warning>

## The OOB callback: the authenticate endpoint

**`POST /open-api-corp/card3ds/v1/authenticate`** — challenge-result confirmation, returning the cardholder's verification outcome to DCS. **Callable on the OOB path only.**

**Request parameters**

| Field         | Type   | Required | Description                                                                                                                                  |
| ------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `challengeId` | String | Yes      | ≤64; the challenge ID, from the webhook's `data.challengeId`                                                                                 |
| `action`      | String | Yes      | ≤16; the cardholder's verification result, full enum: `APPROVE` (cardholder verified) / `REJECT` (cardholder declined / verification failed) |
| `operateTime` | String | No       | ≤32; when the cardholder acted, format `yyyy-MM-dd'T'HH:mm:ssXXX`; recorded verbatim for audit, with no server-side fallback                 |

**Response data**

| Field                | Type   | Description                                           |
| -------------------- | ------ | ----------------------------------------------------- |
| `challengeId`        | String | The challenge ID (echoes the request's `challengeId`) |
| **Request examples** |        |                                                       |

```json theme={null}
// Scenario 1: OOB challenge — return the cardholder's verification result (this endpoint is OOB-only)
{
  "challengeId": "5185740066240790531",
  "action": "APPROVE",
  "operateTime": "2026-08-19T10:30:00+08:00"
}
// Scenario 2: OTP_DELEGATE challenges have no callback — calling this endpoint by mistake returns CARD_3DS_CHALLENGE_NOT_FOUND (see response scenario 2)
```

**Response examples**

```json theme={null}
// Scenario 1: OOB challenge accepted (repeating the same result is idempotent — the response matches the first)
{
  "code": "SYS_SUCCESS",
  "message": null,
  "data": {
    "challengeId": "5185740066240790531"
  }
}
// Scenario 2: calling this endpoint against an OTP_DELEGATE challenge (no callback path — rejected)
{
  "code": "CARD_3DS_CHALLENGE_NOT_FOUND",
  "message": "challenge not found",
  "data": null
}
```

**Error codes**

| Error code                     | Description                                                                                                                                                                                                            |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CARD_3DS_CHALLENGE_NOT_FOUND` | Challenge does not exist / does not belong to this partner / is not an OOB challenge (e.g. calling this endpoint against an OTP\_DELEGATE challenge) — all three cases share one code, with no differentiation exposed |

<Note>
  **Idempotency**: repeating the same result for the same `challengeId` returns idempotently, with a response identical to the first — retries need no dedup design on your side.
</Note>

<Info>
  **Compliance note · HKMA 3DS requirements**: under the Hong Kong Monetary Authority's requirements published on 14 April 2025, online credit card transactions must be verified through the bank's app. The HKMA's press release of 1 August 2024 extended the requirement to 32 banks and 10 stored-value facility (SVF) operators. Partners serving Hong Kong cardholders are advised to adopt the OOB (in-app) mode to align with this direction. References: [HKMA, "New Anti-Digital Fraud Measures: E-Banking Security ABC"](https://brdr.hkma.gov.hk/eng/doc-ldg/docId/getPdf/20250411-1-EN/20250411-1-EN.pdf), [HKAB statement](https://www.hkab.org.hk/en/news/press-release/318).
</Info>

## Next steps

* The authorization and settlement main line after the challenge passes: [Real-time authorization and settlement](./realtime-authorization)
* The transaction-event landscape and authorization semantics: [Transactions · Overview](./authorization-and-3ds)
