Seamless Payment (Snap-Checkout)

This guide explains how merchants with an existing Snap Checkout integration can enable payments within MiniApp.


Integration NeededDetails
Mini App FrontendDisplay Snap payment page on frontend
Mini App BackendAcquire Snap transaction token on your backend

Sequence Diagram:

Mini app payments Flow diagram

671

1. User Initiate Order

  • The user decides to place an order in the mini app front end process for order.

2. [SNAP-CHECKOUT API] Acquiring Transaction Token on Backend

3: [SNAP-CHECKOUT API] Displaying Snap Payment Page on Frontend

4: [SNAP-CHECKOUT API] Notify

  • Once the payment is complete. Super App backend will notify the Mini App Backend by v1.0/debit/notify
  • The contract for the api can be found here.

New GoPay Merchants:

If you have not integrated with GoPay or have integrated without following the SNAP-CHECKOUT API convention, the following points apply :

  • You must first onboard SNAP-CHECKOUT API convention following below integration steps

Existing GoPay Merchants:

If you have already integrated with GoPay and follow the SNAP-CHECKOUT API convention, the following points apply :

  • There is no change in the already integrated SNAP-CHECKOUT API
  • For Obtain Transaction Token request, the new object in the existing contract needs to be added under gopay.pop_id. The value for this is shared by the GoPay Team in the MiniApp Workbook sent via email.


1. Acquiring Transaction Token on Backend

API request should be done from merchant backend to acquire Snap transaction token by providing payment information and Server Key. There are at least three components that are required to obtain the Snap token which are explained in the table given below.

ElementDescription
Server KeyAPI server key. For more details, refer to Retrieving API Access Keys
order_idUnique transaction order ID, defined from your side. One ID could be used only once for the order of the material. Allowed character are Alphanumeric, dash(-), underscore(_), tilde (~), and dot (.) String, max 50.
gross_amount

Total amount of transaction, defined from your side. Integer.

When creating 1st transaction, the gross_amount is still required.
Although, then the actual accepted payment amount is allowed to be different that the initial gross_amount, so customer can flexibly pay with any acceptable amount.

Charge API Sample Request


Endpoints

EnvironmentMethodURL
SandboxPOSThttps://app.sandbox.midtrans.com/snap/v1/transactions
ProductionPOSThttps://app.midtrans.com/snap/v1/transactions

HTTP Headers

Acceptapplication/json
Content-Typeapplication/json
AuthorizationBasic AUTH_STRING

AUTH_STRING: Base64Encode("YourServerKey"+":")


📘

Midtrans API validates HTTP request by using Basic Authentication method. The username is your Server Key while the password is empty. The authorization header value is represented by AUTH_STRING. AUTH_STRING is base-64 encoded string of your username and password separated by colon symbol (:). For more details, refer to API Authorization and Headers.

GoPay Object

"gopay": {
  "pop_id": "990407c8-7c2b-4998-8ef8-0bc67c0c6c55"
}
ParameterDescription
pop_idFor MiniApp payments, this parameter is mandatory to determine the Point of Purchase (POP).

Sample Request

curl --location --request POST 'https://app.midtrans.com/snap/v1/transactions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic auth' \
--data '{
    "transaction_details": {
        "order_id": "test-123",
        "gross_amount": 100000
    },
    "gopay": {
        "pop_id": "<pop_id>"
    },
    "callbacks": {
        "finish": "https://www.google.com",
        "error": "https://www.facebook.com"
    }
}'
/*Install Midtrans PHP Library (https://github.com/Midtrans/midtrans-php)
composer require midtrans/midtrans-php
                              
Alternatively, if you are not using **Composer**, you can download midtrans-php library 
(https://github.com/Midtrans/midtrans-php/archive/master.zip), and then require 
the file manually.   

require_once dirname(__FILE__) . '/pathofproject/Midtrans.php'; */

//SAMPLE REQUEST START HERE

// Set your Merchant Server Key
\Midtrans\Config::$serverKey = 'YOUR_SERVER_KEY';
// Set to Development/Sandbox Environment (default). Set to true for Production Environment (accept real transaction).
\Midtrans\Config::$isProduction = false;
// Set sanitization on (default)
\Midtrans\Config::$isSanitized = true;
// Set 3DS transaction for credit card to true
\Midtrans\Config::$is3ds = true;

$params = array(
    'transaction_details' => array(
        'order_id' => rand(),
        'gross_amount' => 10000,
    ),
    'customer_details' => array(
        'first_name' => 'budi',
        'last_name' => 'pratama',
        'email' => '[email protected]',
        'phone' => '08111222333',
    ),
);

$snapToken = \Midtrans\Snap::getSnapToken($params);
/*Install midtrans-client (https://github.com/Midtrans/midtrans-nodejs-client) NPM package.
npm install --save midtrans-client*/

//SAMPLE REQUEST START HERE

const midtransClient = require('midtrans-client');
// Create Snap API instance
let snap = new midtransClient.Snap({
        // Set to true if you want Production Environment (accept real transaction).
        isProduction : false,
        serverKey : 'YOUR_SERVER_KEY'
    });

let parameter = {
    "transaction_details": {
        "order_id": "YOUR-ORDERID-123456",
        "gross_amount": 10000
    },
    "credit_card":{
        "secure" : true
    },
    "customer_details": {
        "first_name": "budi",
        "last_name": "pratama",
        "email": "[email protected]",
        "phone": "08111222333"
    }
};

snap.createTransaction(parameter)
    .then((transaction)=>{
        // transaction token
        let transactionToken = transaction.token;
        console.log('transactionToken:',transactionToken);
    })
/*Install midtrans-java (https://github.com/Midtrans/midtrans-java) library.
If you are using Maven as the build automation tool for your project,
please add the following dependency to your project's build definition (pom.xml).
<dependencies>
    <dependency>
      <groupId>com.midtrans</groupId>
      <artifactId>java-library</artifactId>
      <version>3.0.0</version>
    </dependency>
</dependencies>
  
If you are using Gradle as the build tool for your project, 
please add the following dependency to your project's build definition (build.gradle).

dependencies {
    implementation 'com.midtrans:java-library:3.0.0'
}

You can also check the functional test 
(https://github.com/Midtrans/midtrans-java/blob/master/library/src/test/java/com/midtrans/java/CoreApiTest.java) for more examples.
*/

//SAMPLE REQUEST START HERE

import com.midtrans.Midtrans;
import com.midtrans.httpclient.SnapApi;
import com.midtrans.httpclient.error.MidtransError;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.json.JSONObject;

public class MidtransExample {

    public static void main(String[] args) throws MidtransError {
      // Set serverKey to Midtrans global config
      Midtrans.serverKey = "YOUR_SERVER_KEY";

      // Set value to true if you want Production Environment (accept real transaction).
      Midtrans.isProduction = false;

      // Create params JSON Raw Object request
      public Map<String, Object> requestBody() {
          UUID idRand = UUID.randomUUID();
          Map<String, Object> params = new HashMap<>();

          Map<String, String> transactionDetails = new HashMap<>();
          transactionDetails.put("order_id", idRand);
          transactionDetails.put("gross_amount", "265000");

          Map<String, String> creditCard = new HashMap<>();
          creditCard.put("secure", "true");

          params.put("transaction_details", transactionDetails);
          params.put("credit_card", creditCard);

          return params;
      }

      // Create Token and then you can send token variable to FrontEnd,
      // to initialize Snap JS when customer click pay button
      String transactionToken = SnapApi.createTransactionToken(requestBody())
    }
}
#Install midtransclient(https://github.com/Midtrans/midtrans-python-client) PIP package
#pip install midtransclient

#SAMPLE REQUEST START HERE

import midtransclient
# Create Snap API instance
snap = midtransclient.Snap(
    # Set to true if you want Production Environment (accept real transaction).
    is_production=False,
    server_key='YOUR_SERVER_KEY'
)
# Build API parameter
param = {
    "transaction_details": {
        "order_id": "test-transaction-123",
        "gross_amount": 200000
    }, "credit_card":{
        "secure" : True
    }, "customer_details":{
        "first_name": "budi",
        "last_name": "pratama",
        "email": "[email protected]",
        "phone": "08111222333"
    }
}

transaction = snap.create_transaction(param)

transaction_token = transaction['token']
/*Import Midtrans Go module package to your project. Via terminal:
go get -u github.com/midtrans/midtrans-go

and/or on your project code:
import (
    "github.com/midtrans/midtrans-go"
    "github.com/midtrans/midtrans-go/coreapi"
    "github.com/midtrans/midtrans-go/snap"
    "github.com/midtrans/midtrans-go/iris"
)*/

//SAMPLE REQUEST START HERE

// 1. Initiate Snap client
var s = snap.Client
s.New("YOUR-SERVER-KEY", midtrans.Sandbox)
// Use to midtrans.Production if you want Production Environment (accept real transaction).

// 2. Initiate Snap request param
req := & snap.RequestParam{
    TransactionDetails: midtrans.TransactionDetails{
      OrderID:  "YOUR-ORDER-ID-12345",
      GrossAmt: 100000,
    }, 
    CreditCard: &snap.CreditCardDetails{
      Secure: true,
    },
    CustomerDetail: &midtrans.CustomerDetails{
      FName: "John",
      LName: "Doe",
      Email: "[email protected]",
      Phone: "081234567890",
    },
  }

// 3. Execute request create Snap transaction to Midtrans Snap API
snapResp, _ := s.CreateTransaction(req)

For MiniApp payments, pop_id is mandatory. Transactions without pop_id may not be routed correctly within the MiniApp flow.

The pop_id (Point of Purchase ID) will be shared via email in the MiniApp Workbook document after requesting a new MiniApp creation.

Sample Response

{
  "token":"66e4fa55-fdac-4ef9-91b5-733b97d1b862",
  "redirect_url":"https://app.sandbox.midtrans.com/snap/v2/vtweb/66e4fa55-fdac-4ef9-91b5-733b97d1b862"
}

List of Response Code

Status CodeDescriptionExample
201Successful creation of Snap token."token":"66e4fa55-fdac-4ef9-91b5-733b97d1b862"
401Failed to create a token, as wrong authorization is sent."Access denied, please check client or server key"
4xxFailed to create a token, as wrong parameter is sent. Follow the error_message and check your parameter."transaction_details.gross_amount is not equal to the sum of item_details"
5xxFailed to create a token, because of Midtrans internal error. Most of the time this is temporary, you can retry later."Sorry, we encountered internal server error. We will fix this soon."


2. Displaying Snap Payment Page on Frontend


Javascript Method

📘

Tips

  • If you are using frontend framework such as ReactJS and struggling to include the script tag, please refer to this recommendation.
  • To ensure that Snap modal is displayed correctly on a mobile device, please include the viewport meta tag inside your <head> tag. The most common implementation is as follows :
    <meta name="viewport" content="width=device-width, initial-scale=1">
  • Optionally, you can also use JavaScript callbacks to handle payment events triggered from customer finishing interaction with Snap payment page on frontend.

Include snap.js library into your payment page HTML. The table given below describes the components which are required to display Snap payment page.

ElementDescription
Client KeyThe Client Key. For more details refer to Retrieving API Access Keys
snap.js urlhttps://app.sandbox.midtrans.com/snap/snap.js
transaction tokenRetrieved from backend in previous step

Enter your Client Key as the value of data-client-key attribute in snap.js script tag.

Pop Up Mode

Display the Snap Checkout modal by overlaying it over your page (pop up). Start the payment process by calling window.snap.pay with transaction token.


<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- @TODO: replace SET_YOUR_CLIENT_KEY_HERE with your client key -->
    <script type="text/javascript"
      src="https://app.sandbox.midtrans.com/snap/snap.js"
      data-client-key="SET_YOUR_CLIENT_KEY_HERE"></script>
    <!-- Note: replace with src="https://app.midtrans.com/snap/snap.js" for Production environment -->
  </head>

  <body>
    <button id="pay-button">Pay!</button>

    <script type="text/javascript">
      // For example trigger on button clicked, or any time you need
      var payButton = document.getElementById('pay-button');
      payButton.addEventListener('click', function () {
        // Trigger snap popup. @TODO: Replace TRANSACTION_TOKEN_HERE with your transaction token
        window.snap.pay('TRANSACTION_TOKEN_HERE');
        // customer will be redirected after completing payment pop-up
      });
    </script>
  </body>
</html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- @TODO: replace SET_YOUR_CLIENT_KEY_HERE with your client key -->
    <script type="text/javascript"
      src="https://app.sandbox.midtrans.com/snap/snap.js"
      data-client-key="SET_YOUR_CLIENT_KEY_HERE"></script>
    <!-- Note: replace with src="https://app.midtrans.com/snap/snap.js" for Production environment -->
  </head>

  <body>
    <button id="pay-button">Pay!</button>

    <script type="text/javascript">
      // For example trigger on button clicked, or any time you need
      var payButton = document.getElementById('pay-button');
      payButton.addEventListener('click', function () {
        // Trigger snap popup. @TODO: Replace TRANSACTION_TOKEN_HERE with your transaction token
        window.snap.pay('TRANSACTION_TOKEN_HERE', {
          onSuccess: function(result){
            /* You may add your own implementation here */
            alert("payment success!"); console.log(result);
          },
          onPending: function(result){
            /* You may add your own implementation here */
            alert("wating your payment!"); console.log(result);
          },
          onError: function(result){
            /* You may add your own implementation here */
            alert("payment failed!"); console.log(result);
          },
          onClose: function(){
            /* You may add your own implementation here */
            alert('you closed the popup without finishing the payment');
          }
        })
      });
    </script>
  </body>
</html>

Learn more about Snap's Javascript Callback here and Snap's Javascript optional parameters here..

After following the steps given above, the sample Snap page is displayed as shown below.

Snap Embedded - Mobile Implementation via Mobile View

After the payment is completed, customer is redirected back to Finish URL. It is specified on callbacks object during Acquiring Transaction Token on Backend or via Midtrans Dashboard, under menu Settings > Snap Preference > System Settings >Finish URL .


3. Notify

Some sample HTTP notifications for a successful transaction on different payment methods are given below.

Tips: You can "scroll right" on the below tab's header to see more payment method's tabs.

{
  "transaction_time": "2020-01-09 18:27:19",
  "transaction_status": "capture",
  "transaction_id": "57d5293c-e65f-4a29-95e4-5959c3fa335b",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "16d6f84b2fb0468e2a9cf99a8ac4e5d803d42180347aaa70cb2a7abb13b5c6130458ca9c71956a962c0827637cd3bc7d40b21a8ae9fab12c7c3efe351b18d00a",
  "payment_type": "credit_card",
  "order_id": "Postman-1578568851",
  "merchant_id": "G141532850",
  "masked_card": "48111111-1114",
  "gross_amount": "10000.00",
  "fraud_status": "accept",
  "eci": "05",
  "currency": "IDR",
  "channel_response_message": "Approved",
  "channel_response_code": "00",
  "card_type": "credit",
  "bank": "bni",
  "approval_code": "1578569243927"
}
{
  "transaction_time": "2021-06-15 18:45:13",
  "transaction_status": "settlement",
  "transaction_id": "513f1f01-c9da-474c-9fc9-d5c64364b709",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "2496c78cac93a70ca08014bdaaff08eb7119ef79ef69c4833d4399cada077147febc1a231992eb8665a7e26d89b1dc323c13f721d21c7485f70bff06cca6eed3",
  "settlement_time": "2021-06-15 18:45:28",
  "payment_type": "gopay",
  "order_id": "Order-5100",
  "merchant_id": "G141532850",
  "gross_amount": "154600.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "transaction_type": "on-us",
  "transaction_time": "2021-06-23 14:02:42",
  "transaction_status": "settlement",
  "transaction_id": "513f1f01-c9da-474c-9fc9-d5c64364b709",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "2496c78cac93a70ca08014bdaaff08eb7119ef79ef69c4833d4399cada077147febc1a231992eb8665a7e26d89b1dc323c13f721d21c7485f70bff06cca6eed3",
  "settlement_time": "2021-06-23 14:06:48",
  "payment_type": "qris",
  "order_id": "qris-01",
  "merchant_id": "G141532850",
  "merchant_cross_reference_id": "0197f326-973a-743c-b0a9-77cfc3c95d53",
  "issuer": "gopay",
  "gross_amount": "5539.00",
  "fraud_status": "accept",
  "currency": "IDR",
  "acquirer": "gopay"
}
{
  "transaction_time": "2021-06-23 13:28:05",
  "transaction_status": "settlement",
  "transaction_id": "513f1f01-c9da-474c-9fc9-d5c64364b709",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "2496c78cac93a70ca08014bdaaff08eb7119ef79ef69c4833d4399cada077147febc1a231992eb8665a7e26d89b1dc323c13f721d21c7485f70bff06cca6eed3",
  "settlement_time": "2021-06-23 13:28:21",
  "payment_type": "shopeepay",
  "order_id": "shopeepay-01",
  "merchant_id": "G141532850",
  "gross_amount": "16700.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "transaction_time": "2021-06-23 11:18:59",
  "transaction_status": "settlement",
  "transaction_id": "6fd88567-62da-43ff-8fe6-5717e430ffc7",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "0c0df82489931602577d9e434966c0540249b7c0aeaae2b718305af89a11e2bf9b4008aba07d1b3b248b15b4fbecdd15e81dbb2648b974efc4e0656e8c976094",
  "settlement_time": "2021-06-23 11:20:06",
  "permata_va_number": "8562000087926752",
  "payment_type": "bank_transfer",
  "order_id": "permata-va-01",
  "merchant_id": "G141532850",
  "gross_amount": "185000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "va_numbers": [
    {
      "va_number": "333333333333333",
      "bank": "bca"
    }
  ],
  "transaction_time": "2021-06-23 11:27:20",
  "transaction_status": "settlement",
  "transaction_id": "9aed5972-5b6a-401e-894b-a32c91ed1a3a",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "fe5f725ea770c451017e9d6300af72b830a668d2f7d5da9b778ec2c4f9177efe5127d492d9ddfbcf6806ea5cd7dc1a7337c674d6139026b28f49ad0ea1ce5107",
  "settlement_time": "2021-06-23 11:27:50",
  "payment_type": "bank_transfer",
  "payment_amounts": [],
  "order_id": "bca-va-01",
  "merchant_id": "G141532850",
  "gross_amount": "100000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "va_numbers": [
    {
      "va_number": "3333000000111111",
      "bank": "bni"
    }
  ],
  "transaction_time": "2021-06-23 11:41:33",
  "transaction_status": "settlement",
  "transaction_id": "9aed5972-5b6a-401e-894b-a32c91ed1a3a",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "fe5f725ea770c451017e9d6300af72b830a668d2f7d5da9b778ec2c4f9177efe5127d492d9ddfbcf6806ea5cd7dc1a7337c674d6139026b28f49ad0ea1ce5107",
  "settlement_time": "2021-06-23 11:42:03",
  "payment_type": "bank_transfer",
  "payment_amounts": [
    {
      "paid_at": "2021-06-23 11:42:02",
      "amount": "150000.00"
    }
  ],
  "order_id": "bni-va-01",
  "merchant_id": "G141532850",
  "gross_amount": "150000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "va_numbers": [
    {
      "va_number": "123456789123456789",
      "bank": "bri"
    }
  ],
  "transaction_time": "2021-06-23 11:53:34",
  "transaction_status": "settlement",
  "transaction_id": "9aed5972-5b6a-401e-894b-a32c91ed1a3a",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "fe5f725ea770c451017e9d6300af72b830a668d2f7d5da9b778ec2c4f9177efe5127d492d9ddfbcf6806ea5cd7dc1a7337c674d6139026b28f49ad0ea1ce5107",
  "settlement_time": "2021-06-23 11:53:34",
  "payment_type": "bank_transfer",
  "payment_amounts": [],
  "order_id": "bri-va-01",
  "merchant_id": "G141532850",
  "gross_amount": "300000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "transaction_time": "2021-06-23 11:57:49",
  "transaction_status": "settlement",
  "transaction_id": "883af6a4-c1b4-4d39-9bd8-b148fcebe853",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "bbceb3724b0b2446c59435795039fed2d249d3438f06bf90c999cc9d383b95170b7b58f9412fba25ce7756da8075ab1d78a48800156380a62dc84eb22b3f7de9",
  "settlement_time": "2021-06-23 11:58:44",
  "payment_type": "echannel",
  "order_id": "mandiri-bill-01",
  "merchant_id": "G141532850",
  "gross_amount": "30000.00",
  "fraud_status": "accept",
  "currency": "IDR",
  "biller_code": "70012",
  "bill_key": "990000000260"
}
{
  "transaction_time": "2021-06-23 13:13:21",
  "transaction_status": "settlement",
  "transaction_id": "991af93c-1049-4973-b38f-d6052c72e367",
  "store": "indomaret",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "a198f93ac43cf98171dcb4bd0323c7e3afbee77a162a09e2381f0a218c761a4ef0254d7650602971735c486fea2e8e9c6d41ee65d6a53d65a12fb1c824e86f9f",
  "settlement_time": "2021-06-23 13:13:56",
  "payment_type": "cstore",
  "payment_code": "300063000630006300",
  "order_id": "indomaret-01",
  "merchant_id": "G141532850",
  "gross_amount": "336000.00",
  "currency": "IDR",
  "approval_code": "ABC0101BCA02"
}
{
  "transaction_time": "2021-06-23 13:17:01",
  "transaction_status": "settlement",
  "transaction_id": "991af93c-1049-4973-b38f-d6052c72e367",
  "store": "alfamart",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "a198f93ac43cf98171dcb4bd0323c7e3afbee77a162a09e2381f0a218c761a4ef0254d7650602971735c486fea2e8e9c6d41ee65d6a53d65a12fb1c824e86f9f",
  "settlement_time": "2021-06-23 13:18:04",
  "payment_type": "cstore",
  "payment_code": "300063000630006300",
  "order_id": "alfamart-01",
  "merchant_id": "G141532850",
  "gross_amount": "662000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}
{
  "transaction_time": "2021-06-23 10:55:24",
  "transaction_status": "settlement",
  "transaction_id": "b3a40398-d95d-4bb9-afe8-9a57bc0786ea",
  "status_message": "midtrans payment notification",
  "status_code": "200",
  "signature_key": "35c4111539e184b268b7c1cd62a9c254e5d27c992c8fd55084f930b69b09eaafcfe14b0d512c697648295fdb45de777e1316b401f4729846a91b3de88cde3f05",
  "settlement_time": "2021-06-23 10:56:55",
  "payment_type": "akulaku",
  "order_id": "akulaku-01",
  "merchant_id": "G141532850",
  "gross_amount": "130000.00",
  "fraud_status": "accept",
  "currency": "IDR"
}

Additional APIs

  1. Refund API
  2. Cancel API
  3. Get Transaction Status API
  4. Payment Notification API