---
title: "Card Payment With 3DS Verification"
source_url: https://docs.rapyd.net/en/card-payment-with-3ds-verification.html
lang: en
---

# Card Payment With 3DS Verification

A card issuer can require a customer on your eCommerce website to perform an additional security step: three-domain secure (3DS) verification.

[3DS](https://docs.rapyd.net/en/glossary.md#UUID-945d98cf-adae-e1cf-2606-c7fae8b4a7e1_rds "Three-Domain Secure") is a protocol for verifying an identity in card-not-present transactions. Your customer is redirected to a separate website with instructions for completing the 3DS verification. When the card transaction is completed, the 3DS website redirects the customer back to a URL (that you supply) indicating success or failure, and notifies Rapyd. Rapyd then updates your website back end.

Common benefits include:

- Easier and quicker payment process results in better checkout experience for your customer.
- Liabilities owing to any  [chargebacks](https://docs.rapyd.net/en/glossary.md#UUID-945d98cf-adae-e1cf-2606-c7fae8b4a7e1_chargeback "Chargeback") are passed from the merchant to the issuer.
- Reduces the risk of fraud and makes payments safer.
- No extra costs for the additional step of 3DS verification which provides increased security for your transactions.

> **Note:**
>
> Only clients with [PCI-DSS](https://docs.rapyd.net/en/glossary.md#UUID-945d98cf-adae-e1cf-2606-c7fae8b4a7e1_dss "Payment Card Industry Data Security Standard") certification can handle personal identifying information for cards. This method is available to merchants who have signed a special agreement with Rapyd.

### Card Payment Checkout

The following screenshot represents a Card Payment Checkout with SG (Singapore) and SGD (Singapore Dollar) for the country and currency as described in Find Available Payment Methods.

1. Enter the card details.
2. Click **Place Your Order**.

   ![64808358d207a.png](image/img-3de95a880ffea96070f369f28a0f2deb.png)
3. Complete the 3DS Verification.

   ![6480835babcf5.png](image/img-2cc7e672bef1aeb23b714f419cf66274.png)
4. Redirect to the **payment success** page.

### Card Payments With 3DS Verification Workflow

Finding the specific card payment methods you'll accept and the corresponding required fields that customers fill out is described under How it Works.

### Step 1: Card Payment With 3DS Verification Process

![cards-3ds-process.jpg](image/img-a5ec354d20e9678c1a9c5da11401b8d1.jpg)

1. The customer completes the card payment in checkout.
2. You send Rapyd the 3DS payment request with the customer ID starting with **cus_**.
3. Rapyd receives the request and redirects the customer to the 3DS verification URL.
4. You display the 3DS URL to the customer.

### Step 2: Card Payment With 3DS Payment Process

![card-3ds-payment-process.jpg](image/img-e49d1b4fac263f3508641470b8c0a01d.jpg)

1. The customer completes the card payment 3DS verification.
2. The 3DS website redirects the customer to a success or error URL.
3. Rapyd processes the payment and sends the response.
4. You display the purchase success page.

### Card Payment With 3DS Verification Message Sequences

The message sequence diagrams below describe how information is exchanged between Rapyd, the merchant, the merchant's customers, and the card network.

Card Payment With 3DS Verification - Success

![card-payment-with-3ds-authentication---success.svg](image/img-668d9dcddc22cb99f6b7e8f88f71e3d1.svg)

Card Payment With 3DS Verification - Failure

![payment-with-3ds-verification---verification-failure.svg](image/img-8f2c2b9be22f5271f7b15f7731a281e5.svg)

### How Card Payments With 3DS Work

> **Note:**
>
> To use the [sandbox](https://docs.rapyd.net/en/glossary.md#UUID-945d98cf-adae-e1cf-2606-c7fae8b4a7e1_sandbox "Sandbox") to simulate a payment that requires 3DS authentication, set the 'amount' between **1000.00** and **1999.99**.

### Find Available Payment Methods

> **Note:**
>
> 3DS layer is not available in all regions. It is automatically triggered when a regulatory mandate such as [PSD2](https://docs.rapyd.net/en/glossary.md#UUID-945d98cf-adae-e1cf-2606-c7fae8b4a7e1_psd "Directive on Payment Services") requires it.
>
> For more details on how to prevent fraudulent transactions, see [Rapyd Protect](https://docs.rapyd.net/en/rapyd-protect.md "Rapyd Protect").

Check which card payment methods are accepted in the customer's country. To do that, use [List Payment Methods by Country](https://docs.rapyd.net/en/list-payment-methods-by-country.md "List Payment Methods by Country") with the following parameters:

Description of Query Parameters

| Query Parameter | Description |
| --- | --- |
| country | Enter **SG** as the country code. |
| currency | Enter **SGD** as the currency code. |

### List Payment Methods by Country Request

Request for a list of all available SG payment methods.

- - Request

    - ```
      // Request URL: GET https://sandboxapi.rapyd.net/v1/payment_methods/country?country=SG&currency=SGD

      // Message body absent
      ```
- - .NET Core

    - ```
      using System;

      namespace RapydApiRequestSample
      {
          class Program
          {
              static void Main(string[] args)
              {
                  try
                  {
                      string result = RapydApiRequestSample.Utilities.MakeRequest("GET", "/v1/payment_methods/country?country=SG&currency=SGD");

                      Console.WriteLine(result);
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Error completing request: " + e.Message);
                  }
              }
          }
      }
                        
      ```
- - JavaScript

    - ```
      const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest;

      async function main() {
        try {
          const result = await makeRequest('GET', '/v1/payment_methods/country?country=SG&currency=SGD');

          console.log(result);
        } catch (error) {
          console.error('Error completing request', error);
        }
      }
                        
      ```
- - PHP

    - ```
      <?php
      $path = $_SERVER['DOCUMENT_ROOT'];
      $path .= "/<path-to-your-utility-file>/utilities.php";
      include($path);

      try {
          $object = make_request('get', '/v1/payment_methods/country?country=SG&currency=SGD');
          var_dump($object);
      } catch (Exception $e) {
          echo "Error: $e";
      }
      ?>
      ```
- - Python

    - ```
      from pprint import pprint

      from utilities import make_request

      country = 'SG'
      currency = 'SGD'
      results = make_request(method='get', path=f'/v1/payment_methods/country?country={country}&currency={currency}')
      pprint(results)
                        
      ```

### List Payment Methods by Country Response

[List Payment Methods by Country](https://docs.rapyd.net/en/list-payment-methods-by-country.md "List Payment Methods by Country") describes the fields in the response.

- - Response

    - ```

      {
          "status": {
              "error_code": "",
              "status": "SUCCESS",
              "message": "",
              "response_code": "",
              "operation_id": "cfa35a73-aa0b-4e7e-839c-4c3b6149edd7"
          },
          "data": [{
                  "type": "sg_debit_cup_card",
                  "name": "Union Pay Debit",
                  "category": "card",
                  "image": "https://iconslib.rapyd.net/checkout/sg_debit_cup_card.png",
                  "country": "sg",
                  "payment_flow_type": "card",
                  "currencies": [
                      "SGD"
                  ],
                  "status": 1,
                  "is_cancelable": false,
                  "payment_options": [{
                          "name": "customer",
                          "type": "customer",
                          "regex": "",
                          "description": "make sure a customer was created with first_name, last_name and email",
                          "is_required": true,
                          "is_updatable": false
                      }
                  ],
                  "is_expirable": true,
                  "is_online": false,
                  "minimum_expiration_seconds": 600,
                  "maximum_expiration_seconds": 604800
              }
          ]
      }
                        
      ```

The `data` section of the response shows that a Union Pay debit card is an acceptable payment method.

> **Note:**
>
> A full API response lists many payment methods.

### Find Required Fields for the Payment Method

You need to find out which fields you have to fill for the payment method. To do that, use the [Get Payment Method Required Fields](https://docs.rapyd.net/en/get-payment-method-required-fields.md "Get Payment Method Required Fields") with the following parameter:

Description of Path Parameters

| Path Parameter | Description |
| --- | --- |
| type | Enter **sg_debit_cup_card** as the payment method type. |

### Get Payment Method Required Fields Request

Request for the set of required fields for a Union Pay debit card.

- - Request

    - ```
      // Request URL: GET https://sandboxapi.rapyd.net/v1/payment_methods/sg_debit_cup_card/required_fields

      // Message body absent
      ```
- - .NET Core

    - ```
      using System;

      namespace RapydApiRequestSample
      {
          class Program
          {
              static void Main(string[] args)
              {
                  try
                  {
                      string result = RapydApiRequestSample.Utilities.MakeRequest("GET", "/v1/payment_methods/sg_debit_cup_card/required_fields");

                      Console.WriteLine(result);
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Error completing request: " + e.Message);
                  }
              }
          }
      }
                          
      ```
- - JavaScript

    - ```
      const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest;

      async function main() {
        try {
          const result = await makeRequest('GET', '/v1/payment_methods/sg_debit_cup_card/required_fields');

          console.log(result);
        } catch (error) {
          console.error('Error completing request', error);
        }
      }
      ```
- - PHP

    - ```
      <?php
      $path = $_SERVER['DOCUMENT_ROOT'];
      $path .= "/<path-to-your-utility-file>/utilities.php";
      include($path);

      try {
          $object = make_request('get', '/v1/payment_methods/sg_debit_cup_card/required_fields');
          var_dump($object);
      } catch (Exception $e) {
          echo "Error: $e";
      }
      ?>  
      ```
- - Python

    - ```
      from pprint import pprint

      from utilities import make_request

      payment_method = 'sg_debit_cup_card'
      results = make_request(method='get', path=f'/v1/payment_methods/{payment_method}/required_fields')
      pprint(results)
                          
      ```

### Get Payment Method Required Fields Response

[Get Payment Method Required Fields](https://docs.rapyd.net/en/get-payment-method-required-fields.md "Get Payment Method Required Fields") describes the fields in the response.

- - Response

    - ```
      {
          “status”: {
              “error_code”: “”,
              “status”: “SUCCESS”,
              “message”: “”,
              “response_code”: “”,
              “operation_id”: “3b7a2391-6612-478e-b79e-38d7f8d33ff9”
          },
          “data”: {
              “type”: “sg_debit_cup_card”,
              “fields”: [
                  {
                      “name”: “name”,
                      “type”: “string”,
                      “regex”: “”,
                      “is_required”: true,
                      “instructions”: “card holder name”
                  },
                  {
                      “name”: “number”,
                      “type”: “string”,
                      “regex”: “”,
                      “is_required”: true,
                      “instructions”: “card number”
                  },
                  {
                      “name”: “expiration_month”,
                      “type”: “string”,
                      “regex”: “”,
                      “is_required”: true,
                      “instructions”: “expiration month as string, 01-12"
                  },
                  {
                      “name”: “expiration_year”,
                      “type”: “string”,
                      “regex”: “”,
                      “is_required”: true,
                      “instructions”: “expiration year in to digits as string, 18-99”
                  },
                  {
                      “name”: “cvv”,
                      “type”: “string”,
                      “regex”: “”,
                      “is_required”: true,
                      “instructions”: “card cvv”
                  }
              ],
              “payment_method_options”: [
                  {
                      “name”: “3d_required”,
                      “type”: “string”,
                      “regex”: “”,
                      “description”: “”,
                      “is_required”: false,
                      “is_updatable”: false
                  }
              ],
              “payment_options”: [
                  {
                      “name”: “description”,
                      “type”: “string”,
                      “regex”: “”,
                      “description”: “the description field must be filled in.“,
                      “is_required”: true,
                      “is_updatable”: false
                  },
                  {
                      “name”: “complete_payment_url”,
                      “type”: “string”,
                      “regex”: “”,
                      “description”: “the complete_payment_url field must be filled in.“,
                      “is_required”: true,
                      “is_updatable”: false
                  },
                  {
                      “name”: “error_payment_url”,
                      “type”: “string”,
                      “regex”: “”,
                      “description”: “the error_payment_url field must be filled in.“,
                      “is_required”: true,
                      “is_updatable”: false
                  }
              ],
              “minimum_expiration_seconds”: 600,
              “maximum_expiration_seconds”: 604800
          }
      }
                          
      ```

The response shows that for a SG Union Pay Debit card, you must provide:

- `name`
- `number`
- `expiration_month`
- `expiration_year`
- `cvv`

Ensure that your customer completes these fields.

### Process the Payment

At this point, your customer should have completed the following:

- Selected Union Pay as the payment option.
- Filled in the fields required for paying with the card.

When your customer confirms paying with the card, get Rapyd to process the card payment.

For that, you'll call [Create Payment](https://docs.rapyd.net/en/create-payment.md "Create Payment") with the following parameters:

Description of Body Parameters

| Body Parameter | Description |
| --- | --- |
| payment_method | Enter an object with the following fields:  - `type` - **sg_debit_cup_card** - `fields` - Enter an object with the following fields:  - `name` - **cardholder name**   - `number` - **4111111111111111**   - `expiration_month` - **12**   - `expiration_year` - **29**   - `cvv` - **737** |
| amount | Enter **1,001** as the payment amount. |
| currency | Enter **SGD** as the currency code. |
| capture | Enter **true** as the value. This tells Rapyd to collect the payment for you as soon as possible. |
| error_payment_url | Replace `https://error.example.net` in the example with your real website URL where you want the 3DS site to redirect the customer if the payment fails. |
| complete_payment_url | Replace `https://complete.example.net` in the example with your real website URL where you want the 3DS site to redirect the customer if the payment succeeds. |
| payment_method_options | `"3d_required": "true"` |

### Create Payment Request

Request Rapyd to process your customer's card payment of 1,001 SGD.

- - Request

    - ```
      // Request URL: POST https://sandboxapi.rapyd.net/v1/payments

      // Message body: 
      {
         "amount": 1001,
         "currency": "SGD",
         "payment_method": {
             "type":"sg_debit_cup_card",
             "fields": {
                 "number": "4111111111111111",
                 "expiration_month": "12",
                 "expiration_year": "29",
                 "cvv": "737",
                 "name":"Cardholder Name",
             }
         },
           "payment_method_options": {
              "3d_required": "true"
          },
         "error_payment_url": "https://error.example.net",
         "complete_payment_url": "https://complete.example.net",
         "capture": true
      }
      ```
- - .NET Core

    - ```
      using System;
      using System.Text.Json;

      namespace RapydApiRequestSample
      {
          class Program
          {
              static void Main(string[] args)
              {
                  try
                  {
                      var requestObj = new
                      {
                          amount = 1001,
                          currency = "SGD",
                          payment_method = new
                          {
                              type = "sg_debit_cup_card",
                              fields = new
                              {
                                  number = "4111111111111111",
                                  expiration_month = "12",
                                  expiration_year = "29",
                                  cvv = "737",
                                  name = "Cardholder Name"
                              }
                          },
                          error_payment_url = "https:error.example.net",
                          complete_payment_url = "https:complete.example.net",
                          payment_method_options = new
                          {
                               3d_required = true
                      },
                          capture = true
                      };

                      string request = JsonSerializer.Serialize(requestObj);

                      string result = RapydApiRequestSample.Utilities.MakeRequest("POST", "/v1/payments", request);

                      Console.WriteLine(result);
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Error completing request: " + e.Message);
                  }
              }
          }
                          
      ```
- - JavaScript

    - ```
      const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest;

      async function main() {
        try {
          const body = {
            amount: 1001,
            currency: 'SGD',
            payment_method: {
              type: 'sg_debit_cup_card',
              fields: {
                number: '4111111111111111',
                expiration_month: '12',
                expiration_year: '29',
                cvv: '737',
                name: 'Cardholder Name'
              }
            },
            error_payment_url: 'https://error.example.net',
            complete_payment_url: 'https://complete.example.net',
            "payment_method_options": {        
              "3d_required": true    
          },
            capture: true
          };
          const result = await makeRequest('POST', '/v1/payments', body);

          console.log(result);
        } catch (error) {
          console.error('Error completing request', error);
        }
      }
                          
      ```
- - PHP

    - ```
      <?php
      $path = $_SERVER['DOCUMENT_ROOT'];
      $path .= "/<path-to-your-utility-file>/utilities.php";
      include($path);

      $body = [
          'amount' => 1001,
          'currency' => 'SGD',
          'payment_method' => [
              'type' => 'sg_debit_cup_card',
              'fields' => [
                  'number' => '4111111111111111',
                  'expiration_month' => '12',
                  'expiration_year' => '29'
                  'cvv' => '737',
                  'name' => 'Cardholder Name'
              ]
          ],
          'error_payment_url' => urldecode('https://error_example.net'),
          'complete_payment_url' => urldecode('https://complete_example.net') 
          'payment_method_options'=> [
                  '3d_required => true
          ],
          'capture' => true
      ];

      try {
          $object = make_request('post', '/v1/payments', $body);
          var_dump($object);
      } catch (Exception $e) {
          echo "Error: $e";
      }
      ?>
      ```
- - Python

    - ```
      const makeRequest = require('<path-to-your-utility-file>/utilities').makeRequest;

      from pprint import pprint

      from utilities import make_request

      payment_body = {
          'amount': 1001,
          'currency': 'SGD',
          'payment_method': {
              'type': 'sg_debit_cup_card',
              'fields': {
                  'number': '4111111111111111',
                  'expiration_month': '10',
                  'expiration_year': '29',
                  'cvv': '123',
                  'name': 'Cardholder Name'
              }
          },
          'error_payment_url': 'https://error_example.net',
          'complete_payment_url': 'https://complete_example.net',
          'payment_method_options': {
                  '3d_required: true
          },
          'capture': true
      }

      results = make_request(method='post', path='/v1/payments', body=payment_body)
      pprint(results)
                          
      ```

### Create Payment Response

[Create Payment](https://docs.rapyd.net/en/create-payment.md "Create Payment") describes the fields in the response.

- - Response

    - ```
      {
         {
          "status": {
              "error_code": "",
              "status": "SUCCESS",
              "message": "",
              "response_code": "",
              "operation_id": "74d80a88-90a0-44d7-b08f-31f2b2739eef"
          },
          "data": {
              "id": "payment_2bb5e3d9376663dbecb0086298ffc08c",
              "amount": 0,
              "original_amount": 1001,
              "is_partial": false,
              "currency_code": "SGD",
              "country_code": "SG",
              "status": "ACT",
              "description": "",
              "merchant_reference_id": "",
              "customer_token": "cus_56fe83bb28b1e36a9552d68dfa16e3ff",
              "payment_method": "card_0540e5a4c9b8a4fc6a85bb6c6731c423",
              "payment_method_data": {
                  "id": "card_0540e5a4c9b8a4fc6a85bb6c6731c423",
                  "type": "sg_debit_cup_card",
                  "category": "card",
                  "metadata": null,
                  "image": "",
                  "webhook_url": "",
                  "supporting_documentation": "",
                  "next_action": "3d_verification",
                  "name": "Cardholder Name",
                  "last4": "1111",
                  "acs_check": "unchecked",
                  "cvv_check": "unchecked",
                  "bin_details": {
                      "type": null,
                      "brand": null,
                      "level": null,
                      "issuer": null,
                      "country": null,
                      "bin_number": "411111"
                  },
                  "expiration_year": "29",
                  "expiration_month": "12",
                  "fingerprint_token": "ocfp_2a694038316f52122bbbb3ae926cfda9"
              },
              "auth_code": null,
              "expiration": 1692306562,
              "captured": true,
              "refunded": false,
              "refunded_amount": 0,
              "receipt_email": "",
              "redirect_url": "https://sandboxcheckout.rapyd.net/3ds-payment?token=payment_2bb5e3d9376663dbecb0086298ffc08c",
              "complete_payment_url": "https://rapyd.net",
              "error_payment_url": "https://docs.rapyd.net",
              "receipt_number": "",
              "flow_type": "",
              "address": null,
              "statement_descriptor": "Test Business",
              "transaction_id": "",
              "created_at": 1691701762,
              "metadata": {},
              "failure_code": "",
              "failure_message": "",
              "paid": false,
              "paid_at": 0,
              "dispute": null,
              "refunds": null,
              "order": null,
              "outcome": null,
              "visual_codes": {},
              "textual_codes": {},
              "instructions": [],
              "ewallet_id": "ewallet_db4ad4a76278f94c4a83dd9b28b483ed",
              "ewallets": [
                  {
                      "ewallet_id": "ewallet_db4ad4a76278f94c4a83dd9b28b483ed",
                      "amount": 1001,
                      "percent": 100,
                      "refunded_amount": 0
                  }
              ],
              "payment_method_options": {
                  "3d_required": true
              },
              "payment_method_type": "sg_debit_cup_card",
              "payment_method_type_category": "card",
              "fx_rate": 1,
              "merchant_requested_currency": null,
              "merchant_requested_amount": null,
              "fixed_side": "",
              "payment_fees": null,
              "invoice": "",
              "escrow": null,
              "group_payment": "",
              "cancel_reason": null,
              "initiation_type": "customer_present",
              "mid": "",
              "next_action": "3d_verification",
              "error_code": "",
              "remitter_information": {},
              "save_payment_method": true
          }
      }
                          
      ```

The `data` section of the response shows:

- `amount` is **1001**
- `currency` is  **SGD**
- Your guest customer is automatically assigned a customer ID. The payment method is assigned a payment method ID. Both IDs are unique to this one transaction.
- `captured` is  **true** - the card payment will be collected as soon as possible.
- `redirect_url` is  `https://redirect.example.net`, which is the URL where you redirect your guest customer to complete the payment process.
- `paid` is  **false** and `status` is  **ACT** (active), which indicates that we are still waiting for your guest customer to finish the 3DS process.

### Receive Payment Confirmation

At this point, you have redirected the customer to  `https://redirect.example.net`, which is a 3DS verification site. This site might handle the 3DS verification itself, or it might redirect the customer to the website of their own card. The customer follows the authentication instructions on the screen, which could involve copying the number from an email or an SMS into the web page. When the process is completed successfully, Rapyd sends you a webhook with details of the completed transaction.

Let's take a look at [Payment Completed Webhook](https://docs.rapyd.net/en/payment-completed-webhook.md "Payment Completed Webhook").

- - Webhook

    - ```
        {
          "id": "wh_7f18c2b90892652fe7ff2cb7d0537732",
          "type": "PAYMENT_COMPLETED",
          "data": {
              "id": "payment_2bb5e3d9376663dbecb0086298ffc08c",
            
      //      ...      
            
              "paid": true,
            
      //      ...      
            
              "amount": 1001,
              "status": "CLO",
            
      //      ...      
            
              "currency_code": "SGD",
            
      //      ...      
            
              "customer_token": "cus_56fe83bb28b1e36a9552d68dfa16e3ff",
              "payment_method": "card_0540e5a4c9b8a4fc6a85bb6c6731c423",
            
      //      ...      
            
              "payment_method_type_category": "card"
          },
          "trigger_operation_id": "",
          "status": "NEW",
          "created_at": 1691701778
      }    
            
                      
                        
      ```

The `data` section of the webhook shows:

- `paid` is **true** and `status` is **CLO** (closed), which indicates that the money has been paid.
- `amount` is  **1,001**
- `currency_code` is **SGD**
- The `customer_token` and  `payment_method` are the same as in the Create Payment response.
