# 3D Secure using the Finix API

US only
3D Secure is currently supported for US-based merchants only. Canada support is coming soon.

Authenticate a buyer from your server, with no Finix code in your checkout page.

Use this integration when your server drives checkout, or when you can't add a JavaScript library to your front end. It's also the route for mobile apps until the Finix iOS and Android SDKs support 3D Secure.

## Prerequisites

You need the following:

- The card to authenticate as a Payment Instrument ID. If you have a token from a [tokenization form](/guides/online-payments/payment-tokenization), use it to create a Payment Instrument first.
- The ID of the Merchant the payment is processed under.
- An HTTPS URL on your site to return the buyer to.


## Step 1: Create the 3D Secure Session

Create the session when the buyer is ready to pay, by calling POST /3d_secure_sessions.

Server-side only
This request must originate from your server, not the browser. A client-accessible endpoint is an endpoint anyone can call, which exposes your integration to BIN enumeration attacks and allows an attacker to forge a session and attach it to a payment.

The request accepts the following fields:

| Field | Description |
|  --- | --- |
| `amount` | Required. The amount to authenticate, in cents. This must match the amount you charge. |
| `currency` | Required. The three-letter ISO currency code for the payment. |
| `merchant_id` | Required. The ID of the Merchant the payment is processed under. |
| `payment_instrument_id` | Required for this flow. The ID of the Payment Instrument to authenticate. |
| `redirect_url` | Required for this flow. The HTTPS URL to return the buyer to after authentication. Finix passes it to the hosted page as a redirect parameter. |
| `tags` | Key-value data to store on the session, such as your own order number. |


Example
API Definition
3D Secure Session

```json 3D Secure Session
{
  "id": "3d_secure_session_9hK2mNp4T761RBv8qwLDYc",
  "created_at": "2026-08-13T16:41:12.884210Z",
  "updated_at": "2026-08-13T16:41:13.102994Z",
  "3d_secure_authentication": null,
  "3d_secure_authentication_session_id": "tds_visa_5c21a4de91b7",
  "3d_secure_authentication_url": "https://3ds.evervault.com/?team=team_77f6348bb6fd&app=app_ecd782a41696&session=tds_visa_5c21a4de91b7&redirect=https%3A%2F%2Fexample.com%2F3d-secure%2Freturn",
  "3d_secure_version": null,
  "amount": 92169,
  "authentication_type": null,
  "currency": "USD",
  "failure_code": null,
  "failure_message": null,
  "merchant_id": "MUmfEGv5bMpSJ9k5TFRUjkmm",
  "payment_instrument_id": "PI6iQcTtJNCS8GZAVKYi5Ueb",
  "redirect_url": "https://example.com/3d-secure/return",
  "state": "PENDING",
  "tags": {
    "info": "Create 3DS Session with Payment Instrument"
  }
}
```

The session normally starts in the `PENDING` state, and the five-minute expiry starts at the `created_at` timestamp. If the card is not enrolled in 3DS, the session can return `FAILED` immediately — check `state` before sending the buyer to the authentication URL. In that case, read `failure_code` and `failure_message` for the reason.

## Step 2: Authenticate the buyer

The buyer authenticates with their bank on a page Finix hosts, then returns to your site. Confirm the outcome from your server before you charge anything.

### Send the buyer to the authentication page

The session carries a `3d_secure_authentication_url`. Open it in the buyer's browser, either by redirecting the whole page or by loading the URL in a frame embedded in your checkout.

Treat the URL as opaque. Send the buyer to it exactly as Finix returned it, rather than constructing or parsing it yourself.

What the buyer sees depends on what the issuer decides:

- Low-risk payments authenticate in the background, and the buyer returns without seeing anything.
- Otherwise the issuer presents a challenge, such as a one-time passcode or a prompt in the buyer's banking app.


### Read the result on your return URL

Once authentication finishes, the buyer returns to your `redirect_url` with two query parameters appended:


```text Return URL
https://example.com/3d-secure/return?status=success&session=3d_secure_session_9hK2mNp4T761RBv8qwLDYc
```

| Parameter | Description |
|  --- | --- |
| `status` | How the authentication flow ended. One of `success`, `failure`, or `error`. |
| `session` | The ID of the 3D Secure Session. |


status is not the session state
The `status` parameter has its own lowercase values and is not the session `state`. It reports how the browser flow ended, not what the issuer decided.

### Confirm the outcome from your server

The query parameters arrive through the buyer's browser, where they can be edited, so retrieve the session from your server to confirm what actually happened.

3D Secure Session

```json 3D Secure Session
{
  "id": "3d_secure_session_9hK2mNp4T761RBv8qwLDYc",
  "created_at": "2026-08-13T16:41:12.884210Z",
  "updated_at": "2026-08-13T16:41:58.774391Z",
  "3d_secure_authentication": {
    "cardholder_authentication": "BwABBJQ1AgAAAAAgJDUCAAAAAAA=",
    "electronic_commerce_indicator": "AUTHENTICATED",
    "transaction_id": "EaOMucALHQqLAEGAgk"
  },
  "3d_secure_authentication_session_id": "tds_visa_5c21a4de91b7",
  "3d_secure_authentication_url": "https://3ds.evervault.com/?team=team_77f6348bb6fd&app=app_ecd782a41696&session=tds_visa_5c21a4de91b7&redirect=https%3A%2F%2Fexample.com%2F3d-secure%2Freturn",
  "3d_secure_version": "2.2.0",
  "amount": 92169,
  "authentication_type": "CHALLENGE",
  "currency": "USD",
  "failure_code": null,
  "failure_message": null,
  "merchant_id": "MUmfEGv5bMpSJ9k5TFRUjkmm",
  "payment_instrument_id": "PI6iQcTtJNCS8GZAVKYi5Ueb",
  "redirect_url": "https://example.com/3d-secure/return",
  "state": "SUCCEEDED",
  "tags": {
    "info": "Create 3DS Session with Payment Instrument"
  }
}
```

A `SUCCEEDED` state means authentication ran to completion, not that the buyer was authenticated. Read `electronic_commerce_indicator` to find out whether liability shifts.

Buyers close the tab mid-challenge, lose connectivity, or never return to your site at all. In each of those cases no query parameters reach you, so subscribe to the session webhook and treat it as the record of what happened. For more information, see [3D Secure Session webhooks](/guides/online-payments/fraud-and-risk/3d-secure#3d-secure-session-webhooks).

## Step 3: Run the sale or Authorization

Reference the completed session as `3d_secure_session` on the Transfer or Authorization. Finix reads the authentication values from the session and sends them to the card network with the payment.


```shell Transfer with a 3D Secure Session
curl https://finix.sandbox-payments-api.com/transfers \
    -H "Content-Type: application/json" \
    -H 'Finix-Version: 2022-02-01' \
    -u USsRhsHYZGBPnQw8CByJyEQW:8a14c2f9-d94b-4c72-8f5c-a62908e5b30e \
    -d '{
        "amount": 92169,
        "currency": "USD",
        "merchant": "MUmfEGv5bMpSJ9k5TFRUjkmm",
        "source": "PI6iQcTtJNCS8GZAVKYi5Ueb",
        "3d_secure_session": "3d_secure_session_9hK2mNp4T761RBv8qwLDYc"
    }'
```

A successful request returns a `201 Created` status code, with the response body containing the newly created Transfer resource. To authorize the payment now and capture it later, create an Authorization with the same `3d_secure_session` field, then [capture it](/guides/online-payments/payment-features/auth-and-captures#capturing-an-authorization).

Don't send both 3D Secure fields
`3d_secure_session` and `3d_secure_authentication` are mutually exclusive. Use `3d_secure_session` when Finix runs the authentication, and `3d_secure_authentication` only when you authenticate with [your own vendor](/guides/online-payments/fraud-and-risk/3d-secure/passthrough).

## Next steps

3D Secure Authentication
How 3D Secure works, session webhooks, and best practices.

3D Secure Sessions API
Every field on the 3D Secure Session resource.