Integration Steps for SNAP

Pre-requisite

Please follow the guidelines Preparation / Prerequisite for SNAP API for credentials setup, security and header creation

Sandbox Access

Use https://api-sandbox.durianpay.id/v1.0 as base URL for Sandbox environment and https://api.durianpay.id/v1.0 for Live environment

Step 1: Validate Account Number

Before doing disbursement to the beneficiary. You may want to check whether the account is valid and it's a correct beneficiary. We provide validate account API to check whether the destination account is valid and will also return the account name for you to confirm the disbursement destination. It is currently differentiated for Bank destination and E-wallet destination

beneficiaryAccountName requested by merchant should be the same with bank stated name, that's why we recommend merchant to do account number validation first

📘

Account validation will not immediately return success response but rather Accepted. You will need to hit the API again to get success value. We recommend to try it in: 2s, 10s, 30s, 1m, 5m

The numbers stated above is a guideline only, you can adjust it accordingly based on your system implementation
Please take notes in rare cases, it can take longer to get the final status of a transaction.


Bank Account Validation

Bank Account validation API is used to verify whether a disbursement destination account is valid/ invalid. If the account is valid, it will give information of the destination name according to the the bank/provider.

Request Sample
POST Method , URL: /account-inquiry-external

curl --location 'https://api.durianpay.id/v1.0/account-inquiry-external' \
--header 'X-TIMESTAMP: 2024-05-14T18:54:57+07:00' \
--header 'X-SIGNATURE: pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==' \
--header 'X-PARTNER-ID: partner_id' \
--header 'X-EXTERNAL-ID: random_external_id' \
--header 'CHANNEL-ID: channel_id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI' \
--data '{
    "beneficiaryAccountNo": "087783146495",
    "beneficiaryBankCode": "002",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}'
import requests

url = 'https://api.durianpay.id/v1.0/account-inquiry-external'
headers = {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
}
data = {
    "beneficiaryAccountNo": "087783146495",
    "beneficiaryBankCode": "002",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"beneficiaryAccountNo\": \"087783146495\",\n    \"beneficiaryBankCode\": \"002\",\n    \"partnerReferenceNo\": \"202010290000000000000\",\n    \"additionalInfo\": {\n        \"deviceId\": \"12345679237\",\n        \"channel\": \"mobilephone\"\n    }\n}");
        
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/account-inquiry-external")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
const request = require('request');

const url = 'https://api.durianpay.id/v1.0/account-inquiry-external';
const headers = {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
};
const data = {
    "beneficiaryAccountNo": "087783146495",
    "beneficiaryBankCode": "002",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
};

request.post({
    url: url,
    headers: headers,
    json: data
}, (error, response, body) => {
    if (error) {
        console.error('Error:', error);
    } else {
        console.log(body);
    }
});
require 'uri'
require 'net/http'
require 'json'

url = URI("https://api.durianpay.id/v1.0/account-inquiry-external")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-TIMESTAMP"] = "2024-05-14T18:54:57+07:00"
request["X-SIGNATURE"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-PARTNER-ID"] = "partner_id"
request["X-EXTERNAL-ID"] = "random_external_id"
request["CHANNEL-ID"] = "channel_id"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

data = {
  "beneficiaryAccountNo": "087783146495",
  "beneficiaryBankCode": "002",
  "partnerReferenceNo": "202010290000000000000",
  "additionalInfo": {
      "deviceId": "12345679237",
      "channel": "mobilephone"
  }
}

request.body = data.to_json

response = http.request(request)
puts response.read_body

Response Sample

{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237"
    },
    "beneficiaryAccountName": "",
    "beneficiaryAccountNo": "087783146495",
    "beneficiaryBankCode": "002",
    "beneficiaryBankName": "",
    "currency": "IDR",
    "partnerReferenceNo": "202010290000000000000",
    "responseCode": "2021600",
    "responseMessage": "Request In Progress"
}

E-Wallet Account Validation

Validation for e-wallet account, the general flow is the same except URL used and the bank code.

  • Instead of beneficiaryAccountNo, e-wallet has parameter called customerNumber
  • Instead of beneficiaryBankCode, you need to put e-wallet code inside additionalInfo as platformCode. See here for more information.

Request Sample

POST Method , URL: /emoney/account-inquiry

curl --location 'https://api.durianpay.id/v1.0/emoney/account-inquiry' \
--header 'X-TIMESTAMP: 2024-05-14T18:54:57+07:00' \
--header 'X-SIGNATURE: pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==' \
--header 'X-PARTNER-ID: partner_id' \
--header 'X-EXTERNAL-ID: random_external_id' \
--header 'CHANNEL-ID: channel_id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI' \
--data '{
    "customerNumber": "087783146495",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone",
        "platformCode": "gopay"
    }
}'
import requests

url = 'https://api.durianpay.id/v1.0/emoney/account-inquiry'
headers = {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
}
data = {
    "customerNumber": "087783146495",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone",
        "platformCode": "gopay"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.json())
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"customerNumber\": \"087783146495\",\n    \"partnerReferenceNo\": \"202010290000000000000\",\n    \"additionalInfo\": {\n        \"deviceId\": \"12345679237\",\n        \"channel\": \"mobilephone\",\n    \"platformCode\": \"gopay\"\n    }\n}");   
        
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/emoney/account-inquiry")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
const request = require('request');

const url = 'https://api.durianpay.id/v1.0/emoney/account-inquiry';
const headers = {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
};
const data = {
    "customerNumber": "087783146495",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone",
        "platformCode": "gopay"
    }
};

request.post({
    url: url,
    headers: headers,
    json: data
}, (error, response, body) => {
    if (error) {
        console.error('Error:', error);
    } else {
        console.log(body);
    }
});
require 'uri'
require 'net/http'
require 'json'

url = URI("https://api.durianpay.id/v1.0/emoney/account-inquiry")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-TIMESTAMP"] = "2024-05-14T18:54:57+07:00"
request["X-SIGNATURE"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-PARTNER-ID"] = "partner_id"
request["X-EXTERNAL-ID"] = "random_external_id"
request["CHANNEL-ID"] = "channel_id"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

data = {
    "customerNumber": "087783146495",
    "partnerReferenceNo": "202010290000000000000",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone",
        "platformCode": "gopay"
    }
}

request.body = data.to_json

response = http.request(request)
puts response.read_body

Response Sample

{
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone",
        "platformCode": "gopay"
    },
    "customerNumber": "087783146495",
    "currency": "IDR",
    "customerName": "Jane Doe",
    "partnerReferenceNo": "202010290000000000000",
    "responseCode": "2021600",
    "responseMessage": "Request In Progress"
}

Step 2: Submitting Disbursement

Submit Disbursement API is used to Create Disbursement in Durianpay, like account validation, it's differentiated into Bank Account Transfer API and E-Wallet Account Transfer API. This API is only used to trigger the disbursement and the response will be reflecting that disbursement is accepted and will be processed by Durianpay. To get final status of disbursement, please implement Step 3: Getting Disbursement Final status

📘

Before starting to do disbursement you may need to populate the destination bank that is supported here.

In case of time out or internal server error, merchant can try to submit disbursement with the same partnerReferenceNo to see if previous disbursement was submitted or not.


Bank Account Transfer

Submit a disbursement batch or basically create a disbursement batch. The disbursement needs to be submitted via submit disbursement API.

📘

Submit disbursement will not immediately return success response but rather Accepted. You will need to hit the API again to get success value. We recommend to try it in: 2s, 10s, 30s, 1m, 5m

The numbers stated above is a guideline only, you can adjust it accordingly based on your system implementation
Please take notes in rare cases, it can take longer to get the final status of a transaction.

Request Sample

POST Method , URL: /transfer-interbank

curl --location 'https://api.durianpay.id/v1.0/transfer-interbank' \
--header 'X-TIMESTAMP: 2024-05-14T18:54:57+07:00' \
--header 'X-SIGNATURE: pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==' \
--header 'X-PARTNER-ID: partner_id' \
--header 'X-EXTERNAL-ID: random_external_id' \
--header 'CHANNEL-ID: 95221' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI' \
--data '{
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "beneficiaryAccountName": "Dummy Name",
    "beneficiaryAccountNo": "888801000003301",
    "beneficiaryAddress": "Palembang",
    "beneficiaryBankCode": "002",
    "beneficiaryBankName": "Bank BRI",
    "beneficiaryEmail": "[email protected]",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}'
import requests

url = "https://api.durianpay.id/v1.0/transfer-interbank"
headers = {
    "X-TIMESTAMP": "2024-05-14T18:54:57+07:00",
    "X-SIGNATURE": "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==",
    "X-PARTNER-ID": "partner_id",
    "X-EXTERNAL-ID": "random_external_id",
    "CHANNEL-ID": "channel_id",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"
}
data = {
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "beneficiaryAccountName": "Dummy Name",
    "beneficiaryAccountNo": "888801000003301",
    "beneficiaryAddress": "Palembang",
    "beneficiaryBankCode": "002",
    "beneficiaryBankName": "Bank BRI",
    "beneficiaryEmail": "[email protected]",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"partnerReferenceNo\": \"111111111\",\n    \"amount\": {\n        \"value\": \"20000.00\",\n        \"currency\": \"IDR\"\n    },\n    \"beneficiaryAccountName\": \"Dummy Name\",\n    \"beneficiaryAccountNo\": \"888801000003301\",\n    \"beneficiaryAddress\": \"Palembang\",\n    \"beneficiaryBankCode\": \"002\",\n    \"beneficiaryBankName\": \"Bank BRI\",\n    \"beneficiaryEmail\": \"[email protected]\",\n    \"currency\": \"IDR\",\n    \"customerReference\": \"10052019\",\n    \"transactionDate\": \"2019-07-03T12:08:56-07:00\",\n    \"additionalInfo\": {\n        \"deviceId\": \"12345679237\",\n        \"channel\": \"mobilephone\"\n    }\n}");
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/transfer-interbank")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
const request = require('request');

const options = {
  method: 'POST',
  url: 'https://api.durianpay.id/v1.0/transfer-interbank',
  headers: {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
  },
  body: JSON.stringify({
    partnerReferenceNo: '111111111',
    amount: {
      value: '20000.00',
      currency: 'IDR'
    },
    beneficiaryAccountName: 'Dummy Name',
    beneficiaryAccountNo: '888801000003301',
    beneficiaryAddress: 'Palembang',
    beneficiaryBankCode: '002',
    beneficiaryBankName: 'Bank BRI',
    beneficiaryEmail: '[email protected]',
    currency: 'IDR',
    customerReference: '10052019',
    transactionDate: '2019-07-03T12:08:56-07:00',
    additionalInfo: {
      deviceId: '12345679237',
      channel: 'mobilephone'
    }
  })
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);
  console.log(body);
});
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.durianpay.id/v1.0/transfer-interbank")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["X-Timestamp"] = "2024-05-14T18:54:57+07:00"
request["X-Signature"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-Partner-Id"] = "partner_id"
request["X-External-Id"] = "random_external_id"
request["Channel-Id"] = "channel_id"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

request.body = {
  partnerReferenceNo: "111111111",
  amount: {
    value: "20000.00",
    currency: "IDR"
  },
  beneficiaryAccountName: "Dummy Name",
  beneficiaryAccountNo: "888801000003301",
  beneficiaryAddress: "Palembang",
  beneficiaryBankCode: "002",
  beneficiaryBankName: "Bank BRI",
  beneficiaryEmail: "[email protected]",
  currency: "IDR",
  customerReference: "10052019",
  transactionDate: "2019-07-03T12:08:56-07:00",
  additionalInfo: {
    deviceId: "12345679237",
    channel: "mobilephone"
  }
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts response.body

Response Sample

// Sample response
{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237"
    },
    "amount": {
        "currency": "IDR",
        "value": "20000.00",
    },
    "beneficiaryAccountNo": "888801000003301",
    "beneficiaryBankCode": "002",
    "partnerReferenceNo": "111111111",
    "referenceNo": "dis_item_zqMYiSqsPO",
    "responseCode": "2021800",
    "responseMessage": "Request In Progress",
    "sourceAccountNo": "mer_MsCtIPhqRc8045"
}

E-wallet Account Transfer

📘

For e-wallet, instead of beneficiaryBankCode, you will need to put platformCode inside additionalInfo containing e-wallet code

See this table to see which e-wallet supported and its respective platform code

Request Sample

POST Method, URL: /emoney/topup

curl --location 'https://api.durianpay.id/v1.0/emoney/topup' \
--header 'X-TIMESTAMP: 2024-05-14T18:54:57+07:00' \
--header 'X-SIGNATURE: pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==' \
--header 'X-PARTNER-ID: partner_id' \
--header 'X-EXTERNAL-ID: random_external_id' \
--header 'CHANNEL-ID: channel_id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI' \
--data '{
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "customerName": "Dummy Name",
    "customerNumber": "888801000003301",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "platformCode": "gopay",
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}'
import requests

url = "https://api.durianpay.id/v1.0/emoney/topup"
headers = {
    "X-TIMESTAMP": "2024-05-14T18:54:57+07:00",
    "X-SIGNATURE": "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==",
    "X-PARTNER-ID": "partner_id",
    "X-EXTERNAL-ID": "random_external_id",
    "CHANNEL-ID": "channel_id",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"
}
data = {
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "customerName": "Dummy Name",
    "customerNumber": "888801000003301",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "platformCode": "gopay",
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.text)

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n" +
    "    \"partnerReferenceNo\": \"111111111\",\n" +
    "    \"amount\": {\n" +
    "        \"value\": \"20000.00\",\n" +
    "        \"currency\": \"IDR\"\n" +
    "    },\n" +
    "    \"customerName\": \"Dummy Name\",\n" +
    "    \"customerNumber\": \"888801000003301\",\n" +
    "    \"currency\": \"IDR\",\n" +
    "    \"customerReference\": \"10052019\",\n" +
    "    \"transactionDate\": \"2019-07-03T12:08:56-07:00\",\n" +
    "    \"additionalInfo\": {\n" +
    "        \"platformCode\": \"gopay\",\n" +
    "        \"deviceId\": \"12345679237\",\n" +
    "        \"channel\": \"mobilephone\"\n" +
    "    }\n" +
    "}");
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/emoney/topup")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
const request = require('request');

const options = {
  url: 'https://api.durianpay.id/v1.0/emoney/topup',
  headers: {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
  },
  body: JSON.stringify({
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "customerName": "Dummy Name",
    "customerNumber": "888801000003301",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "platformCode": "gopay",
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
  })
};

request.post(options, (error, response, body) => {
  if (error) throw new Error(error);
  console.log(body);
});
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.durianpay.id/v1.0/emoney/topup")
request = Net::HTTP::Post.new(uri)
request["X-Timestamp"] = "2024-05-14T18:54:57+07:00"
request["X-Signature"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-Partner-Id"] = "partner_id"
request["X-External-Id"] = "random_external_id"
request["Channel-Id"] = "channel_id"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"
request.body = JSON.dump({
    "partnerReferenceNo": "111111111",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "customerName": "Dummy Name",
    "customerNumber": "888801000003301",
    "currency": "IDR",
    "customerReference": "10052019",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "additionalInfo": {
        "platformCode": "gopay",
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}).to_json

response = http.request(request)
puts "Response status code: #{response.code}"
puts "Response body: #{response.body}"

Response Sample

// Sample response
{
    statusCode: 202,
    message: 'Accepted',
    codeBlock: `{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237",
        "platformCode" : "gopay"
    },
    "customerName": "Dummy Name",
    "customerNumber": "087783146495",
    "referenceNo": "dis_item_123",
    "currency": "IDR",
    "partnerReferenceNo": "202010290000000000000",
    "responseCode": "2021600",
    "responseMessage": "Request In Progress"
}

Step 3: Getting Disbursement Final Status

There are two ways to get final status of a disbursement: By doing disbursement status inquiry, or/and implement disbursement status notify

3.1 Disbursement Status Inquiry

📘

Use previous referenceNo or partnerReferenceNo from the original request get disbursement status

Similar to account validation, here are recommended duration to get final disbursement status: 30s, 1m, 5m, 10m, 30m
The numbers stated above is a guideline only, you can adjust it accordingly based on your system implementation. Please take notes in rare cases, it can take longer to get the final status of a transaction.

Bank Account Transfer Inquiry

Request Sample

POST Method , URL: /transfer/status

curl --location 'https://api.durianpay.id/v1.0/transfer/status' \
--header 'X-TIMESTAMP: 2024-05-14T18:54:57+07:00' \
--header 'X-SIGNATURE: pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==' \
--header 'X-PARTNER-ID: partner_id' \
--header 'X-EXTERNAL-ID: random_external_id' \
--header 'CHANNEL-ID: 95221' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI' \
--data '{
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "originalExternalId": "30443786930722726463280097920912",
    "serviceCode": "18",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}'
import requests

url = "https://api.durianpay.id/v1.0/transfer/status"
headers = {
    "X-TIMESTAMP": "2024-05-14T18:54:57+07:00",
    "X-SIGNATURE": "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==",
    "X-PARTNER-ID": "partner_id",
    "X-EXTERNAL-ID": "random_external_id",
    "CHANNEL-ID": "channel_id",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"
}
data = {
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "originalExternalId": "30443786930722726463280097920912",
    "serviceCode": "18",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"originalPartnerReferenceNo\": \"111111111\",\n    \"originalReferenceNo\": \"dis_item_vhLkXOtB0s6619\",\n    \"originalExternalId\": \"30443786930722726463280097920912\",\n    \"serviceCode\": \"18\",\n    \"transactionDate\": \"2019-07-03T12:08:56-07:00\",\n    \"amount\": {\n        \"value\": \"20000.00\",\n        \"currency\": \"IDR\"\n    },\n    \"additionalInfo\": {\n        \"deviceId\": \"12345679237\",\n        \"channel\": \"mobilephone\"\n    }\n}");
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/transfer/status")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());
const request = require('request');

const options = {
  method: 'POST',
  url: 'https://api.durianpay.id/v1.0/transfer/status',
  headers: {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': '95221',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
  },
  body: JSON.stringify({
    originalPartnerReferenceNo: '111111111',
    originalReferenceNo: 'dis_item_vhLkXOtB0s6619',
    originalExternalId: '30443786930722726463280097920912',
    serviceCode: '18',
    transactionDate: '2019-07-03T12:08:56-07:00',
    amount: {
      value: '20000.00',
      currency: 'IDR'
    },
    additionalInfo: {
      deviceId: '12345679237',
      channel: 'mobilephone'
    }
  })
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);
  console.log(body);
});
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.durianpay.id/v1.0/transfer/status")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["X-Timestamp"] = "2024-05-14T18:54:57+07:00"
request["X-Signature"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-Partner-Id"] = "partner_id"
request["X-External-Id"] = "random_external_id"
request["Channel-Id"] = "95221"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

request.body = {
  originalPartnerReferenceNo: "111111111",
  originalReferenceNo: "dis_item_vhLkXOtB0s6619",
  originalExternalId: "30443786930722726463280097920912",
  serviceCode: "18",
  transactionDate: "2019-07-03T12:08:56-07:00",
  amount: {
    value: "20000.00",
    currency: "IDR"
  },
  additionalInfo: {
    deviceId: "12345679237",
    channel: "mobilephone"
  }
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts response.body

📘

There are 3 state of disbursement/transfer: success, processing, and failed

Success will have transaction status "00"
Processing will have transaction status "03"
Failed will have transaction status "06"

The HTTP Code itself might show 200, but the transfer status can be failed, since call to the API is success, but not the transfer, please refer to "latestTransactionStatus" attribute

// Sample Response if transfer is success
{
    statusCode: 200,
    message: 'Success',
    codeBlock: `{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237"
    },
    "amount": {
        "currency": "IDR",
        "value": "12345678"
    },
    "beneficiaryAccountNo": "123123123",
    "beneficiaryBankCode": "002",
    "currency": "IDR",
    "latestTransactionStatus": "00",
    "originalExternalId": "30443786930722726463280097920912",
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "previousResponseCode": "2021800",
    "referenceNumber": "123123",
    "responseCode": "2003600",
    "responseMessage": "Successful",
    "serviceCode": "18",
    "sourceAccountNo": "123123",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "transactionId": "123123",
    "transactionStatusDesc": "success"
    }
}
// Sample Response if transfer is still processing
  {
    statusCode: 200,
    message: 'Success',
    codeBlock: `{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237"
    },
    "amount": {
        "currency": "IDR",
        "value": "20000.00",
    },
    "beneficiaryAccountNo": "123123123",
    "beneficiaryBankCode": "002",
    "currency": "IDR",
    "latestTransactionStatus": "03",
    "originalExternalId": "30443786930722726463280097920912",
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "previousResponseCode": "2021800",
    "referenceNumber": "123123",
    "responseCode": "2003600",
    "responseMessage": "OK",
    "serviceCode": "18",
    "sourceAccountNo": "123123",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "transactionId": "123123",
    "transactionStatusDesc": "processing"
    }
}
// Sample Response if transfer is failed
  {
    statusCode: 200,
    message: 'Success',
    codeBlock: `{
    "additionalInfo": {
        "channel": "mobilephone",
        "deviceId": "12345679237"
    },
    "amount": {
        "currency": "IDR",
        "value": "20000.00",
    },
    "beneficiaryAccountNo": "123123123",
    "beneficiaryBankCode": "002",
    "currency": "IDR",
    "latestTransactionStatus": "06",
    "originalExternalId": "30443786930722726463280097920912",
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "previousResponseCode": "2021800",
    "referenceNumber": "123123",
    "responseCode": "2003600",
    "responseMessage": "OK",
    "serviceCode": "18",
    "sourceAccountNo": "123123",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "transactionId": "123123",
    "transactionStatusDesc": "failed"
    }
}

E-wallet Transfer Inquiry Status

Request Sample

POST Method , URL: /emoney/account-inquiry

require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.durianpay.id/v1.0/transfer/status")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["X-Timestamp"] = "2024-05-14T18:54:57+07:00"
request["X-Signature"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-Partner-Id"] = "partner_id"
request["X-External-Id"] = "random_external_id"
request["Channel-Id"] = "channel_id"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

request.body = {
  originalPartnerReferenceNo: "111111111",
  originalReferenceNo: "dis_item_vhLkXOtB0s6619",
  originalExternalId: "30443786930722726463280097920912",
  serviceCode: "18",
  transactionDate: "2019-07-03T12:08:56-07:00",
  amount: {
    value: "20000.00",
    currency: "IDR"
  },
  additionalInfo: {
    deviceId: "12345679237",
    channel: "mobilephone"
  }
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts response.body
import requests

url = "https://api.durianpay.id/v1.0/transfer/status"
headers = {
    "X-TIMESTAMP": "2024-05-14T18:54:57+07:00",
    "X-SIGNATURE": "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==",
    "X-PARTNER-ID": "partner_id",
    "X-EXTERNAL-ID": "random_external_id",
    "CHANNEL-ID": "channel_id",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"
}
data = {
    "originalPartnerReferenceNo": "111111111",
    "originalReferenceNo": "dis_item_vhLkXOtB0s6619",
    "originalExternalId": "30443786930722726463280097920912",
    "serviceCode": "18",
    "transactionDate": "2019-07-03T12:08:56-07:00",
    "amount": {
        "value": "20000.00",
        "currency": "IDR"
    },
    "additionalInfo": {
        "deviceId": "12345679237",
        "channel": "mobilephone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"originalPartnerReferenceNo\": \"111111111\",\n    \"originalReferenceNo\": \"dis_item_vhLkXOtB0s6619\",\n    \"originalExternalId\": \"30443786930722726463280097920912\",\n    \"serviceCode\": \"18\",\n    \"transactionDate\": \"2019-07-03T12:08:56-07:00\",\n    \"amount\": {\n        \"value\": \"20000.00\",\n        \"currency\": \"IDR\"\n    },\n    \"additionalInfo\": {\n        \"deviceId\": \"12345679237\",\n        \"channel\": \"mobilephone\"\n    }\n}");
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/transfer/status")
    .post(body)
    .addHeader("X-TIMESTAMP", "2024-05-14T18:54:57+07:00")
    .addHeader("X-SIGNATURE", "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==")
    .addHeader("X-PARTNER-ID", "partner_id")
    .addHeader("X-EXTERNAL-ID", "random_external_id")
    .addHeader("CHANNEL-ID", "channel_id")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI")
    .build();

Response response = client.newCall(request).execute();
System.out.println(response.body().string());

const request = require('request');

const options = {
  method: 'POST',
  url: 'https://api.durianpay.id/v1.0/transfer/status',
  headers: {
    'X-TIMESTAMP': '2024-05-14T18:54:57+07:00',
    'X-SIGNATURE': 'pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ==',
    'X-PARTNER-ID': 'partner_id',
    'X-EXTERNAL-ID': 'random_external_id',
    'CHANNEL-ID': 'channel_id',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI'
  },
  body: JSON.stringify({
    originalPartnerReferenceNo: '111111111',
    originalReferenceNo: 'dis_item_vhLkXOtB0s6619',
    originalExternalId: '30443786930722726463280097920912',
    serviceCode: '18',
    transactionDate: '2019-07-03T12:08:56-07:00',
    amount: {
      value: '20000.00',
      currency: 'IDR'
    },
    additionalInfo: {
      deviceId: '12345679237',
      channel: 'mobilephone'
    }
  })
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);
  console.log(body);
});
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://api.durianpay.id/v1.0/transfer/status")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["X-Timestamp"] = "2024-05-14T18:54:57+07:00"
request["X-Signature"] = "pCA+q832pxHnTPm1Kdbfu1am37J9XFeGH13JGYqHv7Ww4Tb3Hrc5xRew+4y2tN4wiAPnHmvXcJ1Tyf94jK5gHQ=="
request["X-Partner-Id"] = "partner_id"
request["X-External-Id"] = "random_external_id"
request["Channel-Id"] = "channel_id"
request["Authorization"] = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1OTM3NTYsImlhdCI"

request.body = {
  originalPartnerReferenceNo: "111111111",
  originalReferenceNo: "dis_item_vhLkXOtB0s6619",
  originalExternalId: "30443786930722726463280097920912",
  serviceCode: "18",
  transactionDate: "2019-07-03T12:08:56-07:00",
  amount: {
    value: "20000.00",
    currency: "IDR"
  },
  additionalInfo: {
    deviceId: "12345679237",
    channel: "mobilephone"
  }
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts response.body

Response Sample

{
    "amount": {
        "currency": "IDR",
        "value": "12345678.00"
    },
    "latestTransactionStatus": "00",
    "originalPartnerReferenceNo": "2020102900000000000011",
    "originalReferenceNo": "dis_item_SgWsZEAh1m5870",
    "responseCode": "2003900",
    "responseMessage": "Successful",
    "serviceCode": "38",
    "transactionStatusDesc": "success"
}
{
    "amount": {
        "currency": "IDR",
        "value": "12345678.00"
    },
    "latestTransactionStatus": "03",
    "originalPartnerReferenceNo": "2020102900000000000011",
    "originalReferenceNo": "dis_item_SgWsZEAh1m5870",
    "responseCode": "2003900",
    "responseMessage": "Successful",
    "serviceCode": "38",
    "transactionStatusDesc": "processing"
}
{
    "amount": {
        "currency": "IDR",
        "value": "12345678.00"
    },
    "latestTransactionStatus": "06",
    "originalPartnerReferenceNo": "2020102900000000000011",
    "originalReferenceNo": "dis_item_SgWsZEAh1m5870",
    "responseCode": "2003900",
    "responseMessage": "Successful",
    "serviceCode": "38",
    "transactionStatusDesc": "failed"
}

3.2 Disbursement Notify / Callback Handling

Whenever certain transaction actions occur on your Durianpay SNAP Disbursement integration, we trigger events which your application can listen to. This is where webhooks come in. A webhook is a URL on your server where we send payloads for such events. For example, if you implement webhooks, once a disbursement is successful, we will immediately notify your server with a transfer-bank.notify event. Here is a list of events we can send to your webhook URL.

Durianpay will send the webhook to you directly when an event change occurred, followed by 2, 5, 10, 90, 210 minutes retry if the webhook is not acknowledged with 200 OK status.

You can specify your webhook URL on your dashboard Settings - Webhook where we would send POST requests to whenever an event occurs.

Setting Up Webhook

  • Create Webhooks in Settings > Create New

  • Fill up the event you want to subscribe to, give a name to webhook event and add your url which you want us to call

  • You need to configure only the base url, the path will be appended as per the selected webhook

  • Once you click create button, there will be sample webhook from Durianpay to be sent to the URL. In order to successfuly setup a webhook the URL should return 200 OK.

  • Once you receive success notification on setting up webhook, you are ready to accept Durianpay webhook according to the event specified.


Events after Pay Outs:

NameDescription
transfer-bank.notifyThis event is triggered when a disbursement is completed. Only when the money is already sent to the destination.

Webhook Sample

{
  "originalReferenceNo": "dis_item_123",
  "originalPartnerReferenceNo": "123456789",
  "responseCode": "2000000",
  "responseMessage": "Request has been processed successfully",
  "amount": {
    "value": "12345678.00",
    "currency": "IDR"
  },
  "beneficiaryAccountNo": "1234567890",
  "beneficiaryBankCode": "002",
  "sourceAccountNo": "mer_123",
  "additionalInfo": {
    "latestTransactionStatus": "00",
    "transactionStatusDesc": "done"
  }
}

Handling Webhooks

Handle the webhook by checking the following fields in the additionalInfo parameter of the webhook body

latestTransactionStatustransactionStatusDescDescription
00doneThe transaction is successfully completed
06failedThe transaction is failed

Digital Signature Verification

Follow these steps to validate the digital signature of the webhook

  1. Take the signature from HTTP header "X-SIGNATURE"
    The following is an example:
    X-SIGNATURE: VpByUVbCd1rf/K5sMBGJk2Nz2zLsH9L9PWCMzb/ouVB/rVh/wPTfzr4AIfW9LGzyKrXTihS75uIiKqhIRexS9sAsu+AXyPKVULKGBRIZJ1yNdbQQQfUS3HT4sbn+JgLlBWS7DozJGqR5LY6F0cQ8wceErqSGEiHQGut5bpCaUC3wEfDynujO33BIvKLF5Gy9XnDMRVvRs+r6pjlew5uCX0Z3vmYEVCHE/6pWvkvRONhwQfqzSvIc56MVInnPFraz5l0DdendQbHhiCg0VIqhsp/aG7Ubxd2hS3o1PbnKiVjr07/mU5nhKhNlT8WtES7/5zh/Argl2Fkea8X+n70RBQ==
  2. Compose the string to verify
    1. Sample Webhook payload:
      {
        "additionalInfo": {
          "latestTransactionStatus": "00",
          "transactionStatusDesc": "success"
        },
        "amount": {
          "currency": "IDR",
          "value": "10000.00"
        },
        "beneficiaryAccountNo": "3370018285",
        "beneficiaryBankCode": "014",
        "originalPartnerReferenceNo": "1000-1000-1000-1180",
        "originalReferenceNo": "dis_item_Jl2HIglkQN4340",
        "responseCode": "2000000",
        "responseMessage": "Request has been processed successfully",
        "sourceAccountNo": "mer_1HYN9axnbi6806"
      }
      
    2. String To Verify Format:
      <HTTP METHOD> + ":" + <RELATIVE PATH URL> + ":" + LowerCase(HexEncode(SHA-256(Minify(<HTTP BODY>)))) + ":" + <X-TIMESTAMP>
      
    3. Example: POST:/callback/v1.0/transfer/notify:5d2c90ddfdd406117ced5c2b502c05b601d435c7e5440f82e58733fdd5f15b7d:2024-11-07T16:04:55.667+07:00
  3. Verify the correctness of the signature based on SHA-256 with RSA-2048 encryption using PKCS#8 signing against the string to sign with provided Durianpay public key (please take notes that the public key will be different for Sandbox vs Live).
  4. If the verification is correct, you can safely consume the request and return HTTP 200 response.

Script to verify digital signature

/*
script to verify webhook signature
to verify the signature, fill the necessary parametes inside main() method
and run the script using the command

`go run main.go`

*/

package main

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"net/http"
	"strings"
)

func main() {
	// fill data here for the parameters
	requestBody := []byte(`{}`)
	relativeURL := ""
	timestamp := ""
	rsaPublicKey := ""
	xSignature := ""

	err := VerifyWebhookSignature(requestBody, relativeURL, timestamp, rsaPublicKey, xSignature)
	if err != nil {
		fmt.Println("signature verification failed")
		return
	}
	fmt.Println("signature verified")
}

func VerifyWebhookSignature(requestBody []byte, relativeURL string, timestamp string, rsaPublicKey string, xSignature string) (err error) {
	// body should be added to signature as Lowercase(HexEncode(SHA-256(minify(RequestBody))))
	var minifiedRequest bytes.Buffer
	err = json.Compact(&minifiedRequest, requestBody)
	if err != nil {
		fmt.Println("error minifying request body, error: ", err.Error())
		return
	}
	encodedRequest := generateHexEncodedSHA256(minifiedRequest.String())

	// Format -> SHA256withRSA (HTTPMethod + ":" + RelativeUrl + ":" + Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":" + TimeStamp)
	verificationBody := strings.Join([]string{http.MethodPost, relativeURL, strings.ToLower(encodedRequest), timestamp}, ":")

	err = verifySignature([]byte(verificationBody), rsaPublicKey, xSignature)
	if err != nil {
		fmt.Println("error verifying signature, error: ", err.Error())
		return
	}
	return
}

func verifySignature(requestPayload []byte, rsaPublicKey string, signature string) (err error) {
	// base64 decode the signature
	decodedSignature, err := base64.StdEncoding.DecodeString(signature)
	if err != nil {
		fmt.Println("error base64 decoding signature, error: ", err.Error())
		return
	}

	rsaKey, err := getPKIXPublicKey(rsaPublicKey)
	if err != nil {
		fmt.Println("error parsing rsa public key, error: ", err.Error())
		return
	}

	hashed := sha256.Sum256(requestPayload)

	err = rsa.VerifyPKCS1v15(rsaKey, crypto.SHA256, hashed[:], decodedSignature)
	if err != nil {
		fmt.Println("error verifying signature, error: ", err.Error())
		return
	}
	return
}

func generateHexEncodedSHA256(msg string) string {
	h := sha256.New()
	h.Write([]byte(msg))
	return hex.EncodeToString(h.Sum(nil))
}

// getPKIXPublicKey takes in an RSA public key string.
// decode the PEM string and constructs an RSA public key with PKIX format
func getPKIXPublicKey(publicKey string) (rsaPublicKey *rsa.PublicKey, err error) {
	block, _ := pem.Decode([]byte(publicKey))
	if block == nil {
		err = errors.New("no key found")
		fmt.Println("error verifying signature, error: ", err.Error())
		return
	}

	key, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		fmt.Println("error in parsing public key, error: ", err.Error())
		return
	}

	rsaPublicKey, ok := key.(*rsa.PublicKey)
	if !ok {
		err = errors.New("cannot type assert as rsa public key pointer")
		fmt.Println("error parsing public key, error: ", err.Error())
		return
	}
	return
}


Other Supporting API

Balance Inquiry

This API can be used to check merchant's current balance.

Request Sample

POST Method , URL: /balance-inquiry

curl --location 'https://api.durianpay.id/v1.0/balance-inquiry' \
--header 'X-TIMESTAMP: 2023-07-31T10:55:00+07:00' \
--header 'X-SIGNATURE: SlCb5OKordx8WVhAE5bkg4M8U1vbI7hyHb07G/ydStvTIBmNgEzHj8PdLVbp2iWY1k2e/jgwWmKsrIj/AvH9rw==' \
--header 'X-PARTNER-ID: client_8045' \
--header 'X-EXTERNAL-ID: 202001' \
--header 'CHANNEL-ID: 95521' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1Nzk0MjYsImlhdCI6MTcxNTU3ODUyNiwibWVyY2hhbnRfaWQiOiJtZXJfTXNDdElQaHFSYzgwNDUiLCJncmFudF90eXBlIjoiQVVUSE9SSVpBVElPTl9DT0RFIiwiY2xpZW50X2tleSI6ImNsaWVudF84MDQ1In0.H2IMBY0MiGNvjHwVwXoYekajhPocBxflmodiHxbm0XA' \
--data '{
    "partnerReferenceNo": "2020102900000000000001",
    "accountNo": "7382382957893840",
    "bankCardToken": "12312312",
    "additionalInfo": {
        "deviceId": "123456",
        "channel": "phone"
    }
}'
import requests

url = "https://api.durianpay.id/v1.0/balance-inquiry"
headers = {
    "X-TIMESTAMP": "2023-07-31T10:55:00+07:00",
    "X-SIGNATURE": "SlCb5OKordx8WVhAE5bkg4M8U1vbI7hyHb07G/ydStvTIBmNgEzHj8PdLVbp2iWY1k2e/jgwWmKsrIj/AvH9rw==",
    "X-PARTNER-ID": "client_8045",
    "X-EXTERNAL-ID": "202001",
    "CHANNEL-ID": "95521",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1Nzk0MjYsImlhdCI6MTcxNTU3ODUyNiwibWVyY2hhbnRfaWQiOiJtZXJfTXNDdElQaHFSYzgwNDUiLCJncmFudF90eXBlIjoiQVVUSE9SSVpBVElPTl9DT0RFIiwiY2xpZW50X2tleSI6ImNsaWVudF84MDQ1In0.H2IMBY0MiGNvjHwVwXoYekajhPocBxflmodiHxbm0XA"
}
data = {
    "partnerReferenceNo": "2020102900000000000001",
    "accountNo": "7382382957893840",
    "bankCardToken": "12312312",
    "additionalInfo": {
        "deviceId": "123456",
        "channel": "phone"
    }
}

response = requests.post(url, headers=headers, json=data)
print(response.text)
OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n    \"partnerReferenceNo\": \"2020102900000000000001\",\n    \"accountNo\": \"7382382957893840\",\n    \"bankCardToken\": \"12312312\",\n    \"additionalInfo\": {\n        \"deviceId\": \"123456\",\n        \"channel\": \"phone\"\n    }\n}");
Request request = new Request.Builder()
    .url("https://api.durianpay.id/v1.0/balance-inquiry")
    .post(body)
    .addHeader("X-TIMESTAMP", "2023-07-31T10:55:00+07:00")
    .addHeader("X-SIGNATURE", "SlCb5OKordx8WVhAE5bkg4M8U1vbI7hyHb07G/ydStvTIBmNgEzHj8PdLVbp2iWY1k2e/jgwWmKsrIj/AvH9rw==")
    .addHeader("X-PARTNER-ID", "client_8045")
    .addHeader("X-EXTERNAL-ID", "202001")
    .addHeader("CHANNEL-ID", "95521")
    .addHeader("Content-Type", "application/json")
    .addHeader("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1Nzk0MjYsImlhdCI6MTcxNTU3ODUyNiwibWVyY2hhbnRfaWQiOiJtZXJfTXNDdElQaHFSYzgwNDUiLCJncmFudF90eXBlIjoiQVVUSE9SSVpBVElPTl9DT0RFIiwiY2xpZW50X2tleSI6ImNsaWVudF84MDQ1In0.H2IMBY0MiGNvjHwVwXoYekajhPocBxflmodiHxbm0XA")
    .build();

Response response = client.newCall(request).execute();
System.out.println("Response status code: " + response.code());
System.out.println("Response body: " + response.body().string());
const request = require('request');

const url = 'https://api.durianpay.id/v1.0/balance-inquiry';
const headers = {
    'X-TIMESTAMP': '2023-07-31T10:55:00+07:00',
    'X-SIGNATURE': 'SlCb5OKordx8WVhAE5bkg4M8U1vbI7hyHb07G/ydStvTIBmNgEzHj8PdLVbp2iWY1k2e/jgwWmKsrIj/AvH9rw==',
    'X-PARTNER-ID': 'client_8045',
    'X-EXTERNAL-ID': '202001',
    'CHANNEL-ID': '95521',
    'Content-Type': 'application/json',
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJEdXJpYW4gTW9uZXkiLCJleHAiOjE3MTU1Nzk0MjYsImlhdCI6MTcxNTU3ODUyNiwibWVyY2hhbnRfaWQiOiJtZXJfTXNDdElQaHFSYzgwNDUiLCJncmFudF90eXBlIjoiQVVUSE9SSVpBVElPTl9DT0RFIiwiY2xpZW50X2tleSI6ImNsaWVudF84MDQ1In0.H2IMBY0MiGNvjHwVwXoYekajhPocBxflmodiHxbm0XA'
};
const data = {
    "partnerReferenceNo": "2020102900000000000001",
    "accountNo": "7382382957893840",
    "bankCardToken": "12312312",
    "additionalInfo": {
        "deviceId": "123456",
        "channel": "phone"
    }
};

request.post({
    url: url,
    headers: headers,
    json: data
}, (error, response, body) => {
    if (error) {
        console.error('Request error:', error);
    } else {
        console.log('Response status code:', response.statusCode);
        console.log('Response body:', body);
    }
});
require 'net/http'
require 'uri'
require 'json'

url = URI.parse('https://api.durianpay.id/v1.0/access-token/b2b')
headers = {
  'X-TIMESTAMP' => '2024-05-13T15:32:36.422+07:00',
  'X-SIGNATURE' => 'KLJ9KthaIiZSzPqHUMuJRsKOZtYCqqWd5DhfWqYC7OjZ2Qlu0PvQ2wRQF5vfDWsz/qFYEexOXb47+oQBjMhAz4XRNhXBBfwoWxrGTG8iU8EYSDVfChW0NqAWjWIQolhB4UcHn5SybPFRON3rvAOIQTzuEshUA1PNAln8jOKaRmY=',
  'X-CLIENT-KEY' => 'client_id',
  'Content-Type' => 'application/json'
}
data = { 'grantType' => 'AUTHORIZATION_CODE' }

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url.request_uri, headers)
request.body = data.to_json

response = http.request(request)
puts "Response code: #{response.code}"
puts "Response body: #{response.body}"

Sample Response

// Sample Response
{
    statusCode: 200,
    message: 'Success',
    codeBlock: `{
    "accountInfos": [
        {
            "availableBalance": {
                "currency": "IDR",
                "value": "100000.00"
            }
        }
    ],
    "responseCode": "2001100",
    "responseMessage": "Successful"
}

Non SNAP Supporting API

Credentials Setup : Legacy API

List of API: