**Last updated**: 07 April 2026 | [**Change log**](/access/products/payments/changelog/)

# React Native

## 1. Add the threeDS object

Adding the `threeDS` object to your payment request will enable 3DS.

If 3DS authentication is not available/applicable (e.g. subsequent recurring (MIT), Apple Pay) a validation error message will be returned.

Recommended
Recommended key:values for high authentication rates


```JSON
"instruction": {
  ....
  "threeDS": {
    "type": "integrated",
    "mode": "always",
    "challenge": {
      "returnUrl": "http://payment.example.com",
    },
    "deviceData": {
      "acceptHeader": "text/html",
      "userAgentHeader": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0)",
      "browserLanguage": "en-GB",
      "browserScreenHeight": 1200,
      "browserScreenWidth": 900,
      "browserJavaEnabled": true,
      "browserColorDepth": "32",
      "timeZone": "300",
      "browserJavascriptEnabled": true,
      "channel": "browser"
    }
  }
}
```

Minimum
Minimum key:values to enable 3DS


```JSON
"instruction": {
  ....
  "threeDS": {
    "type": "integrated",
    "mode": "always",
    "challenge": {
      "returnUrl": "http://payment.example.com",
    },
    "deviceData": {
      "acceptHeader": "text/html",
      "userAgentHeader": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0)"
    }  
  }
}
```

Full request example
See [how much data to provide](/access/products/payments/enable-features/3ds-authentication#how-much-data-to-provide) for guidance on the values to include in the request related to 3DS, and the impact this may have on authentication rates.

See [how to enable authentication outage exemptions](/access/products/payments/enable-features/3ds-authentication#how-to-enable-authentication-outage-exemptions) to increase the likelihood of receiving a successful authorization (without liability shift) in the event of a 3DS network failure.

View the full API Request schema
## 2.Device Data Collection (DDC)

The [`/payments`](/access/products/payments/openapi/) response will return an outcome of `3dsDeviceDatarequired`. This contains a `JWT`, `URL` and `BIN`. These values will be used for the device data collection form.


```JSON
{
  "transactionReference": "Memory265-13/08/1876",
  "outcome": "3dsDeviceDataRequired",
  "deviceDataCollection": {
    "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiI2NjAzMDA3YWJlMjMxZTM1ZTNmNTRjODkiLCJpc3MiOiI2NjAzMDA3YTE2ZGQ5YTdlNmEwMzM0MDciLCJleHAiOjE3MTIyNDg3MTIsImlhdCI6MTcxMjI0ODExMiwianRpIjoiZjdjZGVhZWUtMTY4MS00NjlhLTgxZmEtMzBkY2MyOTYzODA3In0.T1a6hOCPVVsQmcCKU3eczwmxlHoWK83tUqIJ_VG4fwc",
    "url": "https://centinelapistag.cardinalcommerce.com/V1/Cruise/Collect",
    "bin": "400000"
  },
  "_actions": {
    "supply3dsDeviceData": {
      "href": "https://try.access.worldpay.com/api/payments/eyJrIjoxLCJkIjoiR0ZSM3R2Z1d4OTI5SEdSVlVaWlk0cllQV3p4TU5raU85Y0ZwSkd2b09FWGo0SnVHYXI0MzJqZlM4RHp5UnRaaiJ9/3dsDeviceData",
      "method": "POST"
    }
  }
}
```

### Device Data Collection form

The device data process for React Native uses:

- a hidden [WebView](https://github.com/react-native-webview/react-native-webview)
- an HTML page responsible for interfacing the HTML/JavaScript layer with the React Native layer
- an iframe, embedded in the HTML page
- a secondary HTML page, loaded via the iframe, and used to kickstart the Device Data Collection


1. Install and link the React Native `WebView` component in your application.



```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

1. Add a hidden `WebView` in your React Native application with the source pointing to the HTML page created in the next step.
Also, add an event listener for the `message` event which will be used to catch messages sent from the HTML layer to the React Native layer.


React Native

```javascript React Native
<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-html-page-that-wraps-the-iframe' }}
  onMessage={(event) => {
    // deserialising and extracting JSON data from the event
    console.info(JSON.parse(event.nativeEvent.data));
  }}
  containerStyle={{ position: 'absolute', width: 0, height: 0 }}
/>
```

1. Create and host the HTML page which will be used to interface the HTML/JavaScript layer with the React Native layer.


HTML

```html HTML
<html lang="en">
<head></head>
<body>
</body>
</html>
```

1. Add a script to the HTML page to relay messages, received by `postMessage()` in the HTML page, to the React Native layer.


JavaScript

```javascript JavaScript
<script language="JavaScript">
window.onmessage = (event) => {
  // for Try: https://centinelapistag.cardinalcommerce.com
  // for Production: https://centinelapi.cardinalcommerce.com
  const allowedOrigin = '...';

  // Always verify that the message received is from the expected origin
  if (event.origin !== allowedOrigin) {
    return;
  }

  // the event data must be serialised into a string
  window.ReactNativeWebView.postMessage(JSON.stringify(event.data));
};
</script>
```

1. Add an iframe to the HTML page and set the `src` attribute to the URL of the page that will POST the DDC form. This URL should contain the following query string parameters: `deviceDataCollection.jwt`, `deviceDataCollection.bin` and `deviceDataCollection.url`. Those will be used in the DDC form.


HTML

```html HTML
<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-ddc-form"></iframe>
```

1. Create and host the secondary HTML page that POSTs the DDC form.


HTML

```javascript HTML
<html>
<body>
<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'deviceDataCollection.url' from the device data initialization response -->
<form id="collectionForm" name="devicedata" method="POST" action="https://ddcUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.bin' from the device data initialization response -->
    <input type="hidden" name="Bin" value="555555" />

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.jwt' from the device data initialization response -->
    <input type="hidden" name="JWT" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ" />

</form>

<script>
  window.onload = function() {
    document.getElementById('collectionForm').submit();
  }
</script>
</body>
</html>
```

The [Testing](/access/products/payments/testing) page (3DS tab) contains an example form to submit the device data values. This is useful if using tools such as Postman/Insomnia to test your integration in the early stages.

### Device Data Collection postMessage

Once the DDC form is submitted and is successfully sent to the card issuer, you are notified via a [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) event.

For security, verify the sender's identity using the postMessage `origin` property as detailed [here](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

| Environment | Origin |
|  --- | --- |
| Try | https://centinelapistag.cardinalcommerce.com |
| Production | https://centinelapi.cardinalcommerce.com |


An example postMessage response:

postmessage

```json postmessage
{
    "MessageType": "profile.completed",
    "SessionId": "0_3XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX6b5",
    "Status": true
}
```

| Key | Value |
|  --- | --- |
| `messageType` | `profile.completed` |
| `SessionId` | UUID, not present or `undefined` |
| `Status` | `true` - use the `SessionId` value in `deviceData.collectionReference` as part of the [3dsDeviceData request](/access/products/payments/openapi/3ds-actions/supply3dsdevicedata#3ds-actions/supply3dsdevicedata/request)`false` -  `SessionId` is empty. Either retry DDC or send the 3dsDeviceData request without the `collectionReference`. |


The DDC call typically takes 1-2 seconds. This depends on the latency between the customer's device, the Cardinal servers and, in part, the type of Device Data Collection performed by the different issuers. The 3DS specification has a maximum response time of 10 seconds.

Note
If no postMessage is provided either retry DDC or send the [3dsDeviceData request](/access/products/payments/openapi/3ds-actions/supply3dsdevicedata#3ds-actions/supply3dsdevicedata/request) without the `collectionReference`. We **highly recommend** [providing device data](/access/products/payments/enable-features/3ds-authentication#emvco-required-values) (e.g. browserScreenHeight) in the payment request as well. This will maximize authentication rates in the case of DDC failure.

### Full integration example code

Dependency

```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

React Native

```javascript
<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-html-page-that-wraps-the-iframe' }}
  onMessage={(event) => {
    // deserialising and extracting JSON data from the event
    console.info(JSON.parse(event.nativeEvent.data));
  }}
  containerStyle={{ position: 'absolute', width: 0, height: 0 }}
/>
```

HTML page 1

```javascript
<html>
<body>
<script language="JavaScript">
  window.onmessage = (event) => {
    // for Try: https://centinelapistag.cardinalcommerce.com
    // for Production: https://centinelapi.cardinalcommerce.com
    const allowedOrigin = '...';

    // Always verify that the message received is from the expected origin
    if (event.origin !== allowedOrigin) {
      return;
    }

    // the event data must be serialised into a string
    window.ReactNativeWebView.postMessage(JSON.stringify(event.data));
  };
</script>

<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-ddc-form"></iframe>
</body>
</html>
```

HTML page 2

```javascript
<html>
<body>
<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'deviceDataCollection.url' from the device data initialization response -->
<form id="collectionForm" name="devicedata" method="POST" action="https://ddcUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.bin' from the device data initialization response -->
    <input type="hidden" name="Bin" value="555555" />

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'deviceDataCollection.jwt' from the device data initialization response -->
    <input type="hidden" name="JWT" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiJPcmdVbml0IiwiaXNzIjoiYXBpSWQiLCJleHAiOjE1NjI5MjMzNDYsImlhdCI6MTU2MjkyMzQwNiwianRpIjoiYTAzMWVhOGEtN2E0Zi00YTQwLWI1NjMtOTUzMzYzMzVhZGNmIn0.0IK74OIXBxFsxqeOURJz1TFnz14ZTbFJTdTWo9cHUJQ" />

</form>

<script>
  window.onload = function() {
    document.getElementById('collectionForm').submit();
  }
</script>
</body>
</html>
```

## 3. Continue with the payment

Once device data has been completed use the `supply3dsDeviceData` action (from the `/payments` response) to resume the payment, including the `SessionId` (Aka: `collectionReference`) in the request body.


```JSON
// Action to continue the payment (from /payment response)
"_actions": {
    "supply3dsDeviceData": {
      "href": "https://try.access.worldpay.com/api/payments/eyJrIjoxLCJkIjoiR0ZSM3R2Z1d4OTI5SEdSVlVaWlk0cllQV3p4TU5raU85Y0ZwSkd2b09FWGo0SnVHYXI0MzJqZlM4RHp5UnRaaiJ9/3dsDeviceData",
      "method": "POST"
    }
}
```


```JSON
// Include the sessionId (Aka: collectionReference) in the body
{
  "collectionReference": "0_3XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX6b5"
}
```

If you do not provide a `collectionReference`, you will see an increased number of `challenged` and even `authenticationFailed` outcomes.

For merchants using `3DS premium` where custom rules can be created using Cardinal, you can also get a 3DS outcome of `bypassed` that will cause the payment to proceed straight to authorization after Device Data Collection.

The issuer then performs a risk assessment using a combination of data from the Payments API request and the device data collection above. If it passes the payment will proceed to `authorization`. If not the issuer may request a `challenge` to verify the identity of the customer.

## 4.Challenge and verification

If the response outcome from the `supply3dsDeviceData` action is `3dsChallenged` you must display a challenge screen from the issuer to check the customers identity.


```JSON
{
  "outcome": "3dsChallenged",
  "transactionReference": "Memory265-13/08/1876",
  "authentication": {
    "version": "2.1.0"
  },
  "challenge": {
    "reference": "706hovL8DK1tIGGzQUV1",
    "url": "https://centinelapistag.cardinalcommerce.com/V2/Cruise/StepUp",
    "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJPcmdVbml0SWQiOiI2NjAzMDA3YWJlMjMxZTM1ZTNmNTRjODkiLCJPYmplY3RpZnlQYXlsb2FkIjpmYWxzZSwiaXNzIjoiNjYwMzAwN2ExNmRkOWE3ZTZhMDMzNDA3IiwiUmV0dXJuVXJsIjoiaHR0cDovL3BheW1lbnQuZXhhbXBsZS5jb20iLCJQYXlsb2FkIjoie1wiUGF5bG9hZFwiOlwiZXlKdFpYTnpZV2RsVkhsd1pTSTZJa05TWlhFaUxDSnRaWE56WVdkbFZtVnljMmx2YmlJNklqSXVNUzR3SWl3aWRHaHlaV1ZFVTFObGNuWmxjbFJ5WVc1elNVUWlPaUppTkRKbE5UWmpaaTAyWkRrMkxUUXpNek10T0dJMk5DMWlNbVU0TldZMFpURTFaVGtpTENKaFkzTlVjbUZ1YzBsRUlqb2laV1ZqWldZeE1ETXRNRE13TVMwMFpUbGtMVGsxTmpFdE56ZGlNbVkzTlRFMk5HUmhJaXdpWTJoaGJHeGxibWRsVjJsdVpHOTNVMmw2WlNJNklqQTBJbjBcIixcIkFDU1VybFwiOlwiaHR0cHM6XFwvXFwvMW1lcmNoYW50YWNzc3RhZy5jYXJkaW5hbGNvbW1lcmNlLmNvbVxcL01lcmNoYW50QUNTV2ViXFwvY3JlcS5qc3BcIixcIlRyYW5zYWN0aW9uSWRcIjpcIjcwNmhvdkw4REsxdElHR3pRVVYxXCJ9IiwiZXhwIjoxNzEyMzA2MDk0LCJpYXQiOjE3MTIzMDU0OTQsImp0aSI6IjE4YTIwYzNkLTZhZmMtNDA5My04NGEwLTQ2OGEyYTY5MTE0OCJ9.YEpOuTxnqrXRiHan-givWBd6FfTDJOfNg-h2dF2yA6A",
    "payload": "eyJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJiNDJlNTZjZi02ZDk2LTQzMzMtOGI2NC1iMmU4NWY0ZTE1ZTkiLCJhY3NUcmFuc0lEIjoiZWVjZWYxMDMtMDMwMS00ZTlkLTk1NjEtNzdiMmY3NTE2NGRhIiwiY2hhbGxlbmdlV2luZG93U2l6ZSI6IjA0In0"
  },
  "_actions": {
    "complete3dsChallenge": {
      "href": "https://try.access.worldpay.com/api/payments/eyJrIjoxLCJkIjoiZXlOaXNtU0lzQnVLTm5BQkt1WjEyMVFxeXg2bUZtb2hEcEpFeDdyYXZ3SDE3NFBpUTBsWUpwekptbW9hR3VVSyJ9/3dsChallenges",
      "method": "POST"
    }
  }
}
```

#### Optional MD field

Pass data specific to your checkout session and it will be echoed back in the `challenge.returnUrl` originally provided. This could, for example, be a checkout sessionId. Any value provided must be URL encoded with a maximum of 1024 characters.

### Challenge display

The challenge display for React Native uses:

- a [WebView](https://github.com/react-native-webview/react-native-webview)
- a mobile-friendly HTML page
- a fullscreen iframe, embedded in the mobile-friendly HTML page, used to display the challenge page to the end user
- a secondary HTML page, loaded via the iframe, and used to kickstart the challenge display


1. Install and link the React Native `WebView` component in your application.



```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

1. Add a WebView in your React Native application with the source pointing to the HTML page created in the next step.


React Native

```javascript React Native
<WebView source={{ uri: 'replace-this-with-the-url-of-the-mobile-friendly-page' }} />
```

1. Create and host the mobile-friendly HTML page.


HTML

```html HTML
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0">
</body>
</html>
```

1. Add a fullscreen iframe to the HTML page and set the `src` attribute to the URL of the page that will POST the challenge form.


HTML

```html HTML
<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-challenge-form"
        width="100%" height="100%"
        style="height: 100%; width: 100%; border-width: 0">
</iframe>
```

1. Create and host the secondary HTML page that POSTs the challenge form.


HTML

```html HTML
<html>
<head>
</head>
<body>

<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'challenge.url' from the authentication response -->
<form id="challengeForm" method= "POST" action="https://challengeUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'challenge.jwt' from the authentication response -->
    <input type = "hidden" name= "JWT" value= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1NDQzOGIzYS1iYjUzLTEyY2QtODY0My0xNTM2YmU3M2ZmMzUiLCJpYXQiOiIzODU2NzI5NDgyIiwiaXNzIjoiNWJkOWUwZTQ0NDRkY2UxNTM0MjhjOTQwIiwiT3JnVW5pdElkIjoiNWJkOWI1NWU0NDQ0NzYxYWMwYWYxYzgwIiwiUmV0dXJuVXJsIjoiaHR0cDovL21lcmNoYW50LmV4YW1wbGUuY29tL3RocmVlZHNjaGFsbGVuZ2Vjb21wbGV0ZSIsIlBheWxvYWQiOnsiQUNTVXJsIjoiaHR0cHM6Ly9hY3MuZXhhbXBsZS5jb20vM2RzMi9jaGFsbGVuZ2U_aWQ9MTIzNDU2Nzg5IiwiUGF5bG9hZCI6IlZHaHBjeUJwY3lCaElHSmhjMlVnTmpRZ1pXNWpiMlJsWkNCbGVHRnRjR3hsSUc5bUlHRWdNMFJUSUNKd1lYbHNiMkZrSWc9PSIsIlRyYW5zYWN0aW9uSWQiOiJzUk1QV0NRb1FyRWlWeGVoVG51MCJ9LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlfQ.3Dqjr5MuEC9AG7uvsJCft94-d70NmgR94zIeru8fAYE" />

    <!-- Optional field (max 1024 characters) for you to pass url parameters in the challenge form that will be included/echoed in the response url (`challenge.returnUrl`) after the challenge is complete -->
    <input type="hidden" name="MD" value="merchantSessionId=1234567890" />

</form>

<script>
  window.onload = function() {
    // Auto submit form on page load
    document.getElementById('challengeForm').submit();
  }
</script>

</body>
</html>
```

In addition, after the challenge is completed, if you wish to relay a message, you have sent by `postMessage()` to your mobile-friendly page, to the React Native layer:

1. Use the following JavaScript in your mobile-friendly page to relay the message to React Native.


Javascript

```javascript Javascript
<script language="JavaScript">
window.onmessage = (event) => {
  // Always verify that the message received is from the expected origin
  if (event.origin !== '...') {
    return;
  }

  // the function below uses a tring, so if you wish to send JSON
  // make sure to serialise it using JSON.stringify()
  window.ReactNativeWebView.postMessage(event.data);
};
</script>
```

1. Add an event listener for the `message` event on your `WebView`.


React Native

```javascript React Native
<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-mobile-friendly-page' }}
  onMessage={(event) => {
    // extracting data (string) from the event
    console.info(event.nativeEvent.data);
  }}
/>
```

The [Testing](/access/products/payments/testing) page (3DS tab) contains an example form to submit the challenge values. This is useful if using tools such as Postman/Insomnia to test your integration in the early stages.

### Full integration example code

Dependency

```bash
# 1. Install dependency
npm install react-native-webview

# 2. Link dependency using your preferred method
react-native link react-native-webview

# 3. Ee-install pods
cd ios
pod install
```

React Native

```javascript
// The onMessage event handler is optional and should be added
// only if you wish to relay to the React Native layer
// a message you sent by postMessage() to your mobile-friendly page

<WebView
  source={{ uri: 'replace-this-with-the-url-of-the-mobile-friendly-page' }}
  onMessage={(event) => {
    // extracting data (string) from the event
    console.info(event.nativeEvent.data);
  }}
/>
```

HTML page 1

```javascript
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body style="margin: 0">
<iframe src="replace-this-with-the-url-of-your-page-that-posts-the-challenge-form"
        width="100%" height="100%"
        style="height: 100%; width: 100%; border-width: 0">
</iframe>

<script language="JavaScript">
// This script is optional and should be added
// only if you wish to relay to the React Native layer
// a message you sent by postMessage() to your mobile-friendly page

window.onmessage = (event) => {
  // Always verify that the message received is from the expected origin
  if (event.origin !== '...') {
    return;
  }

  // the function below uses a string, so if you wish to send JSON
  // make sure to serialise it using JSON.stringify()
  window.ReactNativeWebView.postMessage(event.data);
};
</script>
</body>
</html>
```

HTML page 2

```javascript
<html>
<head>
</head>
<body>

<!-- Using your preferred programming language, set the 'action' attribute with the value of the query string parameter containing the 'challenge.url' from the authentication response -->
<form id="challengeForm" method= "POST" action="https://challengeUrl.example.com">

    <!-- Using your preferred programming language, set the 'value' attribute with the value of the query string parameter containing the 'challenge.jwt' from the authentication response -->
    <input type = "hidden" name= "JWT" value= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1NDQzOGIzYS1iYjUzLTEyY2QtODY0My0xNTM2YmU3M2ZmMzUiLCJpYXQiOiIzODU2NzI5NDgyIiwiaXNzIjoiNWJkOWUwZTQ0NDRkY2UxNTM0MjhjOTQwIiwiT3JnVW5pdElkIjoiNWJkOWI1NWU0NDQ0NzYxYWMwYWYxYzgwIiwiUmV0dXJuVXJsIjoiaHR0cDovL21lcmNoYW50LmV4YW1wbGUuY29tL3RocmVlZHNjaGFsbGVuZ2Vjb21wbGV0ZSIsIlBheWxvYWQiOnsiQUNTVXJsIjoiaHR0cHM6Ly9hY3MuZXhhbXBsZS5jb20vM2RzMi9jaGFsbGVuZ2U_aWQ9MTIzNDU2Nzg5IiwiUGF5bG9hZCI6IlZHaHBjeUJwY3lCaElHSmhjMlVnTmpRZ1pXNWpiMlJsWkNCbGVHRnRjR3hsSUc5bUlHRWdNMFJUSUNKd1lYbHNiMkZrSWc9PSIsIlRyYW5zYWN0aW9uSWQiOiJzUk1QV0NRb1FyRWlWeGVoVG51MCJ9LCJPYmplY3RpZnlQYXlsb2FkIjp0cnVlfQ.3Dqjr5MuEC9AG7uvsJCft94-d70NmgR94zIeru8fAYE" />

    <!-- Optional field (max 1024 characters) for you to pass url parameters in the challenge form that will be included/echoed in the response url (`challenge.returnUrl`) after the challenge is complete -->
    <input type="hidden" name="MD" value="merchantSessionId=1234567890" />

</form>

<script>
  window.onload = function() {
    // Auto submit form on page load
    document.getElementById('challengeForm').submit();
  }
</script>

</body>
</html>
```

## 5. Continue with the payment

Once the challenge form has been completed use the action from the `3dsDeviceData` response. No body is required.

If you do not complete the challenge display, the payment will fail when you post the action below.


```JSON
// Action to continue the payment (from /3dsDeviceData response)
"_actions": {
    "complete3dsChallenge": {
      "href": "https://try.access.worldpay.com/api/payments/eyJrIjoxLCJkIjoiZXlOaXNtU0lzQnVLTm5BQkt1WjEyMVFxeXg2bUZtb2hEcEpFeDdyYXZ3SDE3NFBpUTBsWUpwekptbW9hR3VVSyJ9/3dsChallenges",
      "method": "POST"
    }
  }
```

If everything is fine, the payment will proceed. However, if authentication fails or a downstream error prevents authentication details from being returned, you may encounter different outcomes. For a comprehensive overview, please refer to the [Outcome details](#6-outcome-details) below.

## 6. Outcome details

A summary of the 3DS authentication is included in the final payment response.

Authentication successful

```JSON
...
"threeDS": {
  "outcome": "authenticated",
  "issuerResponse": "frictionless"
}
...
```

Authentication outage
See [how to enable authentication outage exemptions](/access/products/payments/enable-features/3ds-authentication#how-to-enable-authentication-outage-exemptions)


```JSON
...
"threeDS": {
  "outcome": "authenticationOutage"
}
...
```

Authentication failed
Issuer failed the authentication following the challenge.


```json
{
	"transactionReference": "05651339-d94e-4fdd-82e9-a41d3df47c7d",
	"outcome": "3dsAuthenticationFailed",
	"authentication": {
		"version": "2.1.0",
		"eci": "07",
		"transactionId": "ec89944d-c5b1-4d4b-b39a-a2dc80dd5565"
	}
}
```

Unavailable
Error/Timeout whilst attempting authentication.


```json
{
	"transactionReference": "700cb517-02c6-4dfe-a9dc-a5f77ae101bb",
	"outcome": "3dsUnavailable"
}
```