Card Payment Integration

Basic integration process of Card Fullpayment (3DS) will be explained below.

Sandbox Environment

All the steps below are using Midtrans Sandbox environment, not Production, to easily test the integration process. Make sure you are switching to Sandbox mode on your Midtrans account dashboard while retrieving Server Key and Client Key. Explained in Getting Started - Preparation

Server Key and Client Key can be retrieved on menu Settings > Access Keys

Testing Payment

To test card transaction as a customer, please use testing credentials described here. Example, card for success scenario:

Card Number: 4811 1111 1111 1114 
CVV: 123 
Expiry: <any future date>

Diagram

Overview of the transaction flow in sequence diagram:

card transaction flow .

Integration Step

  1. Get card token, via frontend.
  2. Send transaction data to API Charge using card token, via backend.
  3. (Conditional) if transaction is 3DS, open 3DS redirect_url with popup/redirect, via frontend.
  4. Handle transaction notification, on backend.

1. Get Card Token

Card token_id is representation of customer's card data, that will be used during a transaction. token_id should be retrieved using MidtransNew3ds JS library on merchant's website frontend, card data will be securely transmitted by frontend javascript to Midtrans API in exchange of card token_id, to avoid risk involved if card data being transmitted to merchant's backend.

Include Midtrans JS

Client Key (from your account's Dashboard) is required for this step. Include Midtrans JS library to our payment page, by adding this script tag:

<script id="midtrans-script" type="text/javascript"
src="https://api.midtrans.com/v2/assets/js/midtrans-new-3ds.min.js" 
data-environment="sandbox" 
data-client-key="<INSERT YOUR CLIENT KEY HERE>"></script>

Important: Change the following attributes.

Attribute Value
data-environment Input sandbox or production (API environment)
data-client-key Input client key from your account's Dashboard

Link: More detailed definition

Get Card Token JS Implementation

To retrieve card token_id, we will be using MidtransNew3ds.getCardToken function. Implement the following Javascript on our payment page.

// card data from customer input, for example
var cardData = {
  "card_number": 4811111111111114,
  "card_exp_month": 02,
  "card_exp_year": 2025,
  "card_cvv": 123,
};

// callback functions
var options = {
  onSuccess: function(response){
    // Success to get card token_id, implement as you wish here
    console.log('Success to get card token_id, response:', response);
    var token_id = response.token_id;
    console.log('This is the card token_id:', token_id);
  },
  onFailure: function(response){
    // Fail to get card token_id, implement as you wish here
    console.log('Fail to get card token_id, response:', response);
  }
};

// trigger `getCardToken` function
MidtransNew3ds.getCardToken(cardData, options);

If all goes well, we will be able to get card token_id inside onSuccess callback function. It will be used as one of JSON parameter for /charge API request.

token_id will need to be passed from frontend to backend for next step, it can be done using AJAX via Javascript, or html form POST, etc. Merchant are free to implement.

Note: This token_id is only valid for 1 transaction. For each card transaction it is required to go through this process, to help ensure card data is transmitted securely. If you are looking to persist/save card token, you may use One-click/Two-clicks feature.



2. Send Transaction Data to API Charge

Charge API request should be done from Merchant's backend. Server Key (from your account's Dashboard) will be needed to authenticate the request.

Charge API request

This is example of /charge API request in Curl, please implement according to your backend language (you can also check our available language libraries). Input token_id retrieved previously.

# sample charge in CURL
curl -X POST \
  https://api.sandbox.midtrans.com/v2/charge \
  -H 'Accept: application/json' \
  -H 'Authorization: Basic <YOUR SERVER KEY ENCODED in Base64>' \
  -H 'Content-Type: application/json' \
  -d '{
  "payment_type": "credit_card",
  "transaction_details": {
    "order_id": "order102",
    "gross_amount": 789000
  },
  "credit_card": {
    "token_id": "<token_id from Get Card Token Step>",
    "authentication": true,
  }
}'

Optional: we can customize credit_card object for other advanced features. For example:

...
  "credit_card": {
    "token_id": "<token_id from Get Card Token Step>",
    "authentication": true, //set true for 3DS, false if you have non 3DS acquiring
    "save_token_id": true //optional, to use one/two click feature
    "installment_term": 12, //optional, to allow installment
    "bank": "bca", //optional, to specify acquiring bank
  }
...

Optional: we can customize transaction_details data. To include data like customer_details, item_details, etc. It's recommended to send as much detail so on report/dashboard those information will be included.

Charge API response

We will get the API response like the following.

{
  "status_code": "201",
  "status_message": "Success, Credit Card transaction is successful",
  "transaction_id": "0bb563a9-ebea-41f7-ae9f-d99ec5f9700a",
  "order_id": "order102",
  "redirect_url": "https://api.sandbox.veritrans.co.id/v2/token/rba/redirect/481111-1114-0bb563a9-ebea-41f7-ae9f-d99ec5f9700a",
  "gross_amount": "789000.00",
  "currency": "IDR",
  "payment_type": "credit_card",
  "transaction_time": "2019-08-27 15:50:54",
  "transaction_status": "pending",
  "fraud_status": "accept",
  "masked_card": "481111-1114",
  "bank": "bni",
  "card_type": "credit"
}
  • If the transaction_status is capture and fraud_status is accept, it means the transaction require no 3DS, and is successfuly complete.

  • If the transaction_status is pending and redirect_url exists, it means the transaction require 3DS, and we will need to proceed to next step, opening 3DS authentication page.

3. Open 3DS Authentication Page

As part of API response, we now have redirect_url. It should be opened (displayed to customer) using MidtransNew3ds JS library on merchant's website frontend.

To open 3DS page we can use MidtransNew3ds.authenticate or MidtransNew3ds.redirect function. Input the redirect_url retrieved previously.

Open 3DS Authenticate Page JS Implementation

var redirect_url = '<redirect_url Retrieved from Charge Response>';

// callback functions
var options = {
  performAuthentication: function(redirect_url){
    // Implement how you will open iframe to display 3ds authentication redirect_url to customer
    popupModal.openPopup(redirect_url);
  },
  onSuccess: function(response){
    // 3ds authentication success, implement payment success scenario
    console.log('response:',response);
    popupModal.closePopup();
  },
  onFailure: function(response){
    // 3ds authentication failure, implement payment failure scenario
    console.log('response:',response);
    popupModal.closePopup();
  },
  onPending: function(response){
    // transaction is pending, transaction result will be notified later via POST notification, implement as you wish here
    console.log('response:',response);
    popupModal.closePopup();
  }
};

// trigger `authenticate` function
MidtransNew3ds.authenticate(redirect_url, options);



/**
 * Example helper functions to open Iframe popup, you may replace this with your own method to open iframe
 * PicoModal library is used:
 * <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/picomodal/3.0.0/picoModal.js"></script>
 */
var popupModal = (function(){
  var modal = null;
  return {
    openPopup(url){
      modal = picoModal({
        content:'<iframe frameborder="0" width="100%" height="100%" src="'+url+'"></iframe>',
        width: "75%", 
        closeButton: false, 
        overlayClose: false,
        escCloses: false
      }).show();
    },
    closePopup(){
      try{
        modal.close();
      } catch(e) {}
    }
  }
}());

/**
 * Alternatively instead of opening 3ds authentication redirect_url using iframe,
 * you can also redirect customer using: 
 * MidtransNew3ds.redirect(redirect_url, { callbackUrl : 'https://mywebsite.com/finish_3ds' });
 **/

3DS Authenticate JSON Response

On the JS callback function, we will get JSON of the transaction result like below.

{
  "status_code": "200",
  "status_message": "Success, Credit Card transaction is successful",
  "transaction_id": "226ba26f-b050-4fc5-aa25-b7f8169bc67b",
  "order_id": "order102",
  "gross_amount": "789000.00",
  "currency": "IDR",
  "payment_type": "credit_card",
  "transaction_time": "2019-08-27 17:22:08",
  "transaction_status": "capture",
  "fraud_status": "accept",
  "approval_code": "1566901334936",
  "eci": "05",
  "masked_card": "481111-1114",
  "bank": "bni",
  "card_type": "credit",
  "channel_response_code": "00",
  "channel_response_message": "Approved"
}

If the transaction_status is capture and fraud_status is accept, it means the transaction is success, and is now complete.

IMPORTANT NOTE: To update transaction status on your backend/database, DO NOT solely rely on frontend callbacks! For security reason to make sure the status is authentically coming from Midtrans, only update transaction status based on HTTP Notification or API Get Status.



4. Handle HTTP Notification

HTTP notification from Midtrans to Merchant backend will also be triggered on event of transaction_status getting updated, to ensure merchant is securely informed. Including if card transaction success or denied. So apart of JSON result above, Merchant backend will be notified by Midtrans.

HTTP POST request with JSON body will be sent to Merchant's notification url configured on dashboard (Settings > Configuration > Notification URL), this is the sample JSON body that will be received by Merchant:

{
  "transaction_time": "2019-08-27 17:22:08",
  "transaction_status": "capture",
  "transaction_id": "226ba26f-b050-4fc5-aa25-b7f8169bc67b",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "9b67a07a82d592bc493f3b775eaae5b1862a8bbaa051cdd31a0a81566c84f2c4d306fe2712c86f8167c4faa594a0e2cbe6ae898491bfaebaf849681ae92264d5",
  "payment_type": "credit_card",
  "order_id": "order102",
  "masked_card": "481111-1114",
  "gross_amount": "789000.00",
  "fraud_status": "accept",
  "eci": "05",
  "currency": "IDR",
  "channel_response_message": "Approved",
  "channel_response_code": "00",
  "card_type": "credit",
  "bank": "bni",
  "approval_code": "1566901334936"
}

Refer here on more details of how to handle HTTP Notification.

Switching To Production

To use Midtrans production environment (accept real payment from real customer), please make sure to:

  1. Switch the API domain URL from api.sandbox.midtrans.com to api.midtrans.com
  2. Switch the Client Key and Server Key from sandbox Dashboard, with keys from production Dashboard.

Done

The card payment integration guide is now complete. Below are some further references.

Description

transaction_status value description for card transaction:

Transaction Status Description
capture Transaction successful, fund has been deducted
pending Transaction is initiated and waiting for further action (3DS by customer)
deny Transaction is denied, further check channel_response_message or fraud_status
expire Transaction failure because customer did not complete 3DS within allowed time

Link: More detailed definition of transaction_status

Link: More detailed definition of fraud_status

Reference

You can also refer to this sample implementation:

For more detail: Complete Core API documentation