Create payment order
Create a disbursement payment order using the Maker/Checker model (BIDV only)
Header Request
| Header | Required | Description |
|---|---|---|
Content-Type | ✓ | application/json |
x-client-id | ✓ | Partner identifier issued by TINGEE. |
x-signature | ✓ | HMAC SHA512 authentication signature. |
x-request-timestamp | ✓ | Time the request is sent (format: yyyyMMddHHmmssSSS, UTC+7) |
Body Parameter
💡 How transaction parameters are applied (Global vs Record-level)
The system accepts parameters at two levels to streamline creating single and batch disbursement orders:
- Global level: Fields such as
transactionType,feeMethod,effectiveDateandcreditAccountType, when passed at the top level of the payload, act as default values for all transactions in the `records` list.- Record level: If these fields are set for an individual item in the `records` array, the system uses that value instead, overriding the global default.
| Field | Type | Required | Description |
|---|---|---|---|
bankBin | string | ✓ | Bank BIN. Always pass 970418 (BIDV's BIN) |
action | string | ✓ | Action performed by the maker of the disbursement order - REQUEST_APPROVAL: Save and submit the disbursement transaction for approval immediately - INIT: Save the disbursement transaction as a draft to submit for approval later |
actionType | string | ✓ | Purpose of the disbursement order - INTERNAL_TRANSFER: Domestic transfer - SALARY: Salary payment - BILL_PAYMENT: Bill / statement payment |
debitAccountNumber | string | ✓ | Payment (debit) account number |
debitAccountName | string | ✕ | Payment account holder name (for reference only, not sent to BIDV). |
transactionType | string | ~ | Transaction type (global) - in-bank : Within the bank - fast-out: NAPAS 247 fast transfer - regular-out: Standard interbank transfer Required if not passed at the record level. |
feeMethod | string | ~ | Fee method (global) - O : The payment account pays the fee - B: The receiving account pays the fee Required, except for INTERNAL_TRANSFER batch orders (records has more than 1 item) — in that case you can pass it per record via records[].feeMethod (default O). For SALARY / BILL_PAYMENT, only this global value is used. |
effectiveDate | string | ~ | Posting date of the transaction at the bank (format: yyyy-MM-dd) (global) Required when action = REQUEST_APPROVAL and actionType is not INTERNAL_TRANSFER. |
remark | string | ~ | Transfer description / general description of the batch (used for SALARY / BILL_PAYMENT; for INTERNAL_TRANSFER the system uses records[].remark). Required when action = REQUEST_APPROVAL and actionType is not INTERNAL_TRANSFER. |
approvalNote | string | ✕ | Note from the maker sent along when submitting for approval (action = REQUEST_APPROVAL). Currently only applies to SALARY / BILL_PAYMENT. |
currency | string | ✕ | Posting currency of the payment account (default: VND) |
creditAccountType | string | ✕ | How the recipient receives the money (global), used when a record does not pass records[].creditAccountType: - ACCOUNT: Receive to an account number - ID: Receive in cash at the counter with an identity document |
records | array | ✓ | List of transaction records to create - Single order: array with 1 item - Batch order: array with n items ( INTERNAL_TRANSFER: up to 500 items) |
Items in records
| Field | Type | Required | Description |
|---|---|---|---|
requestId | string | ✓ | Transaction reference generated by the partner, used to match results (returned in the originId field when querying). Must be unique per transaction. Up to 50 characters (batch orders: up to 30 characters per BIDV rules). |
creditAccountNumber | string | ✓ | Recipient account number. |
creditAccountType | string | ✕ | How the recipient receives the money: - ACCOUNT: Receive to an account number (default) - ID: Receive in cash at the counter with an identity document If omitted, the global creditAccountType value is used. |
creditId | string | ~ | Recipient identity document number (ID card / citizen ID / passport) Required when creditAccountType = ID. |
creditIssueDate | string | ~ | Identity document issue date (format: yyyy-MM-dd) Required when creditAccountType = ID. |
creditIssueAddress | string | ~ | Identity document place of issue Required when creditAccountType = ID. |
creditBranchCode | string | ~ | Recipient bank branch code Required when creditAccountType = ID. |
creditAccountName | string | ✓ | Recipient account holder name (without diacritics, in UPPERCASE, up to 70 characters) |
amount | number | ✓ | Transaction amount (minimum 2,000 VND). |
creditBankBin | string | ✓ | Recipient bank BIN. See Supported banks. |
remark | string | ✓ | Transfer description / transaction details. |
creditCurrency | string | ✕ | Currency of the recipient account (default: VND) |
transactionType | string | ~ | Transaction type (per record) - in-bank: Within the bank - fast-out: NAPAS 247 fast transfer - regular-out: Standard interbank transfer If passed, it takes precedence (overrides the global value). Required if not set at the global level. Note: for a single INTERNAL_TRANSFER order, if it is passed at both levels the system uses the global value. |
effectiveDate | string | ~ | Transaction posting date (per record) Format: yyyy-MM-dd. If passed, it takes precedence (overrides the global value). |
feeMethod | string | ✕ | Fee method (per record, INTERNAL_TRANSFER only) - O: The payment account pays the fee - B: The receiving account pays the fee If passed, it takes precedence (overrides the global value); if neither level passes it, the default is O. |
Sample Request Payload
To match the 4 scenarios in the Response section, below are the corresponding payloads you need to send (they differ only in the action field and the records array).
Click any tab below — all the Code samples and Sample Response sections further down sync automatically to the scenario you pick!
- INIT (Single)
- INIT (Batch)
- REQUEST_APPROVAL (Single)
- REQUEST_APPROVAL (Batch)
{
"actionType": "INTERNAL_TRANSFER",
"transactionType": "in-bank",
"action": "INIT",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"effectiveDate": "2026-06-04",
"records": [
{
"requestId": "TRANS_1006_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"remark": "Chuyen tien"
}
]
}
{
"actionType": "INTERNAL_TRANSFER",
"action": "INIT",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"effectiveDate": "2026-06-04",
"remark": "Chuyen tien nhieu nguoi",
"records": [
{
"requestId": "TRANS_0406_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"transactionType": "in-bank",
"remark": "Thanh toan 1"
},
{
"requestId": "TRANS_0406_A05",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "6666688822",
"creditAccountName": "NGUYEN LOC PHAT",
"amount": 12098,
"creditBankBin": "970406",
"transactionType": "fast-out",
"remark": "Thanh toan 2"
},
{
"requestId": "TRANS_0406_A06",
"creditId": "034201000243",
"creditAccountType": "ID",
"creditAccountName": "TRAN NHAT LE",
"amount": 32987,
"creditBankBin": "970406",
"transactionType": "fast-out",
"creditIssueDate": "2022-06-02",
"creditIssueAddress": "Ha Noi",
"creditBranchCode": "96304004",
"remark": "Thanh toan 3"
}
]
}
{
"actionType": "INTERNAL_TRANSFER",
"action": "REQUEST_APPROVAL",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"approvalNote": "Duyet gap",
"effectiveDate": "2026-06-04",
"records": [
{
"requestId": "TRANS_1006_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"remark": "Chuyen tien"
}
]
}
{
"actionType": "INTERNAL_TRANSFER",
"action": "REQUEST_APPROVAL",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"approvalNote": "Duyet gap",
"effectiveDate": "2026-06-04",
"remark": "Chuyen tien nhieu nguoi",
"records": [
{
"requestId": "TRANS_0406_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"transactionType": "in-bank",
"remark": "Thanh toan 1"
},
{
"requestId": "TRANS_0406_A05",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "6666688822",
"creditAccountName": "NGUYEN LOC PHAT",
"amount": 12098,
"creditBankBin": "970406",
"transactionType": "fast-out",
"remark": "Thanh toan 2"
},
{
"requestId": "TRANS_0406_A06",
"creditId": "034201000243",
"creditAccountType": "ID",
"creditAccountName": "TRAN NHAT LE",
"amount": 32987,
"creditBankBin": "970406",
"transactionType": "fast-out",
"creditIssueDate": "2022-06-02",
"creditIssueAddress": "Ha Noi",
"creditBranchCode": "96304004",
"remark": "Thanh toan 3"
}
]
}
Code samples
- INIT (Single)
- INIT (Batch)
- REQUEST_APPROVAL (Single)
- REQUEST_APPROVAL (Batch)
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/direct-link/create-transfer' \
--header 'accept: application/json' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'x-request-timestamp: 20240509154004003' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'Content-Type: application/json' \
--data '{
"actionType": "INTERNAL_TRANSFER",
"action": "INIT",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"effectiveDate": "2026-06-04",
"records": [
{
"requestId": "TRANS_1006_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"remark": "Chuyen tien"
}
]
}'
import axios from "axios";
import { createHmac } from "crypto";
const CLIENT_ID = "YOUR_CLIENT_ID";
const SECRET_KEY = "YOUR_SECRET_KEY";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
function getTimestamp() {
return new Date(Date.now() + 7 * 60 * 60 * 1000)
.toISOString()
.replace(/[-:TZ.]/g, "")
.slice(0, 17);
}
async function directLinkCreateTransfer() {
const body = {
actionType: "INTERNAL_TRANSFER",
action: "INIT",
bankBin: "970418",
debitAccountNumber: "8600007007",
currency: "VND",
feeMethod: "O",
effectiveDate: "2026-06-04",
records: [
{
requestId: "TRANS_1006_A04",
creditAccountType: "ACCOUNT",
creditAccountNumber: "2220366666",
creditAccountName: "NGUYEN VAN A",
amount: 32987,
creditBankBin: "970418",
remark: "Chuyen tien",
},
],
};
const bodyJson = JSON.stringify(body);
const timestamp = getTimestamp();
const signature = createHmac("sha512", SECRET_KEY)
.update(`${timestamp}:${bodyJson}`)
.digest("hex");
const res = await axios.request({
method: "POST",
url: "https://open-api.tingee.vn/v1/direct-link/create-transfer",
data: bodyJson,
headers: {
accept: "application/json",
"Content-Type": "application/json",
"x-client-id": CLIENT_ID,
"x-request-timestamp": timestamp,
"x-signature": signature,
},
});
console.log(res.data);
}
directLinkCreateTransfer();
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
private const string ClientId = "YOUR_CLIENT_ID";
private const string SecretKey = "YOUR_SECRET_KEY";
private static readonly HttpClient Client = new HttpClient();
public static async Task Main()
{
var body = new
{
actionType = "INTERNAL_TRANSFER",
action = "INIT",
bankBin = "970418",
debitAccountNumber = "8600007007",
currency = "VND",
feeMethod = "O",
effectiveDate = "2026-06-04",
records = new object[]
{
new
{
requestId = "TRANS_1006_A04",
creditAccountType = "ACCOUNT",
creditAccountNumber = "2220366666",
creditAccountName = "NGUYEN VAN A",
amount = 32987,
creditBankBin = "970418",
remark = "Chuyen tien"
}
}
};
// Do not escape non-ASCII / special characters so the JSON matches TINGEE's JSON.stringify
var jsonOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
var timestamp = DateTime.UtcNow.AddHours(7).ToString("yyyyMMddHHmmssfff");
var signature = HmacSha512(SecretKey, $"{timestamp}:{bodyJson}");
var request = new HttpRequestMessage(HttpMethod.Post, "https://open-api.tingee.vn/v1/direct-link/create-transfer");
request.Headers.Add("accept", "application/json");
request.Headers.Add("x-client-id", ClientId);
request.Headers.Add("x-request-timestamp", timestamp);
request.Headers.Add("x-signature", signature);
request.Content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
var response = await Client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
private static string HmacSha512(string key, string message)
{
using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
return Convert.ToHexString(hash).ToLower();
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Main {
private static final String CLIENT_ID = "YOUR_CLIENT_ID";
private static final String SECRET_KEY = "YOUR_SECRET_KEY";
public static void main(String[] args) throws Exception {
// Minified JSON, same as JSON.stringify()
String bodyJson = "{\"actionType\":\"INTERNAL_TRANSFER\",\"action\":\"INIT\",\"bankBin\":\"970418\",\"debitAccountNumber\":\"8600007007\",\"currency\":\"VND\",\"feeMethod\":\"O\",\"effectiveDate\":\"2026-06-04\",\"records\":[{\"requestId\":\"TRANS_1006_A04\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"2220366666\",\"creditAccountName\":\"NGUYEN VAN A\",\"amount\":32987,\"creditBankBin\":\"970418\",\"remark\":\"Chuyen tien\"}]}";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
String timestamp = ZonedDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"))
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String signature = hmacSha512(SECRET_KEY, timestamp + ":" + bodyJson);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://open-api.tingee.vn/v1/direct-link/create-transfer"))
.header("accept", "application/json")
.header("Content-Type", "application/json")
.header("x-client-id", CLIENT_ID)
.header("x-request-timestamp", timestamp)
.header("x-signature", signature)
.method("POST", HttpRequest.BodyPublishers.ofString(bodyJson, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
private static String hmacSha512(String key, String data) throws Exception {
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) hex.append(String.format("%02x", b));
return hex.toString();
}
}
<?php
$clientId = "YOUR_CLIENT_ID";
$secretKey = "YOUR_SECRET_KEY";
$body = [
"actionType" => "INTERNAL_TRANSFER",
"action" => "INIT",
"bankBin" => "970418",
"debitAccountNumber" => "8600007007",
"currency" => "VND",
"feeMethod" => "O",
"effectiveDate" => "2026-06-04",
"records" => [
[
"requestId" => "TRANS_1006_A04",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "2220366666",
"creditAccountName" => "NGUYEN VAN A",
"amount" => 32987,
"creditBankBin" => "970418",
"remark" => "Chuyen tien",
],
],
];
// Do not escape "/" or non-ASCII characters so the JSON matches TINGEE's JSON.stringify
$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
$now = new DateTime("now", new DateTimeZone("Asia/Ho_Chi_Minh"));
$timestamp = $now->format("YmdHisv");
$signature = hash_hmac("sha512", $timestamp . ":" . $bodyJson, $secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://open-api.tingee.vn/v1/direct-link/create-transfer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $bodyJson,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"x-client-id: " . $clientId,
"x-request-timestamp: " . $timestamp,
"x-signature: " . $signature,
],
]);
$response = curl_exec($ch);
if ($response === false) {
echo "cURL Error: " . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/direct-link/create-transfer' \
--header 'accept: application/json' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'x-request-timestamp: 20240509154004003' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'Content-Type: application/json' \
--data '{
"actionType": "INTERNAL_TRANSFER",
"action": "INIT",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"effectiveDate": "2026-06-04",
"remark": "Chuyen tien nhieu nguoi",
"records": [
{
"requestId": "TRANS_0406_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"transactionType": "in-bank",
"remark": "Thanh toan 1"
},
{
"requestId": "TRANS_0406_A05",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "6666688822",
"creditAccountName": "NGUYEN LOC PHAT",
"amount": 12098,
"creditBankBin": "970406",
"transactionType": "fast-out",
"remark": "Thanh toan 2"
},
{
"requestId": "TRANS_0406_A06",
"creditId": "034201000243",
"creditAccountType": "ID",
"creditAccountName": "TRAN NHAT LE",
"amount": 32987,
"creditBankBin": "970406",
"transactionType": "fast-out",
"creditIssueDate": "2022-06-02",
"creditIssueAddress": "Ha Noi",
"creditBranchCode": "96304004",
"remark": "Thanh toan 3"
}
]
}'
import axios from "axios";
import { createHmac } from "crypto";
const CLIENT_ID = "YOUR_CLIENT_ID";
const SECRET_KEY = "YOUR_SECRET_KEY";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
function getTimestamp() {
return new Date(Date.now() + 7 * 60 * 60 * 1000)
.toISOString()
.replace(/[-:TZ.]/g, "")
.slice(0, 17);
}
async function directLinkCreateTransfer() {
const body = {
actionType: "INTERNAL_TRANSFER",
action: "INIT",
bankBin: "970418",
debitAccountNumber: "8600007007",
currency: "VND",
feeMethod: "O",
effectiveDate: "2026-06-04",
remark: "Chuyen tien nhieu nguoi",
records: [
{
requestId: "TRANS_0406_A04",
creditAccountType: "ACCOUNT",
creditAccountNumber: "2220366666",
creditAccountName: "NGUYEN VAN A",
amount: 32987,
creditBankBin: "970418",
transactionType: "in-bank",
remark: "Thanh toan 1",
},
{
requestId: "TRANS_0406_A05",
creditAccountType: "ACCOUNT",
creditAccountNumber: "6666688822",
creditAccountName: "NGUYEN LOC PHAT",
amount: 12098,
creditBankBin: "970406",
transactionType: "fast-out",
remark: "Thanh toan 2",
},
{
requestId: "TRANS_0406_A06",
creditId: "034201000243",
creditAccountType: "ID",
creditAccountName: "TRAN NHAT LE",
amount: 32987,
creditBankBin: "970406",
transactionType: "fast-out",
creditIssueDate: "2022-06-02",
creditIssueAddress: "Ha Noi",
creditBranchCode: "96304004",
remark: "Thanh toan 3",
},
],
};
const bodyJson = JSON.stringify(body);
const timestamp = getTimestamp();
const signature = createHmac("sha512", SECRET_KEY)
.update(`${timestamp}:${bodyJson}`)
.digest("hex");
const res = await axios.request({
method: "POST",
url: "https://open-api.tingee.vn/v1/direct-link/create-transfer",
data: bodyJson,
headers: {
accept: "application/json",
"Content-Type": "application/json",
"x-client-id": CLIENT_ID,
"x-request-timestamp": timestamp,
"x-signature": signature,
},
});
console.log(res.data);
}
directLinkCreateTransfer();
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
private const string ClientId = "YOUR_CLIENT_ID";
private const string SecretKey = "YOUR_SECRET_KEY";
private static readonly HttpClient Client = new HttpClient();
public static async Task Main()
{
var body = new
{
actionType = "INTERNAL_TRANSFER",
action = "INIT",
bankBin = "970418",
debitAccountNumber = "8600007007",
currency = "VND",
feeMethod = "O",
effectiveDate = "2026-06-04",
remark = "Chuyen tien nhieu nguoi",
records = new object[]
{
new
{
requestId = "TRANS_0406_A04",
creditAccountType = "ACCOUNT",
creditAccountNumber = "2220366666",
creditAccountName = "NGUYEN VAN A",
amount = 32987,
creditBankBin = "970418",
transactionType = "in-bank",
remark = "Thanh toan 1"
},
new
{
requestId = "TRANS_0406_A05",
creditAccountType = "ACCOUNT",
creditAccountNumber = "6666688822",
creditAccountName = "NGUYEN LOC PHAT",
amount = 12098,
creditBankBin = "970406",
transactionType = "fast-out",
remark = "Thanh toan 2"
},
new
{
requestId = "TRANS_0406_A06",
creditId = "034201000243",
creditAccountType = "ID",
creditAccountName = "TRAN NHAT LE",
amount = 32987,
creditBankBin = "970406",
transactionType = "fast-out",
creditIssueDate = "2022-06-02",
creditIssueAddress = "Ha Noi",
creditBranchCode = "96304004",
remark = "Thanh toan 3"
}
}
};
// Do not escape non-ASCII / special characters so the JSON matches TINGEE's JSON.stringify
var jsonOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
var timestamp = DateTime.UtcNow.AddHours(7).ToString("yyyyMMddHHmmssfff");
var signature = HmacSha512(SecretKey, $"{timestamp}:{bodyJson}");
var request = new HttpRequestMessage(HttpMethod.Post, "https://open-api.tingee.vn/v1/direct-link/create-transfer");
request.Headers.Add("accept", "application/json");
request.Headers.Add("x-client-id", ClientId);
request.Headers.Add("x-request-timestamp", timestamp);
request.Headers.Add("x-signature", signature);
request.Content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
var response = await Client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
private static string HmacSha512(string key, string message)
{
using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
return Convert.ToHexString(hash).ToLower();
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Main {
private static final String CLIENT_ID = "YOUR_CLIENT_ID";
private static final String SECRET_KEY = "YOUR_SECRET_KEY";
public static void main(String[] args) throws Exception {
// Minified JSON, same as JSON.stringify()
String bodyJson = "{\"actionType\":\"INTERNAL_TRANSFER\",\"action\":\"INIT\",\"bankBin\":\"970418\",\"debitAccountNumber\":\"8600007007\",\"currency\":\"VND\",\"feeMethod\":\"O\",\"effectiveDate\":\"2026-06-04\",\"remark\":\"Chuyen tien nhieu nguoi\",\"records\":[{\"requestId\":\"TRANS_0406_A04\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"2220366666\",\"creditAccountName\":\"NGUYEN VAN A\",\"amount\":32987,\"creditBankBin\":\"970418\",\"transactionType\":\"in-bank\",\"remark\":\"Thanh toan 1\"},{\"requestId\":\"TRANS_0406_A05\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"6666688822\",\"creditAccountName\":\"NGUYEN LOC PHAT\",\"amount\":12098,\"creditBankBin\":\"970406\",\"transactionType\":\"fast-out\",\"remark\":\"Thanh toan 2\"},{\"requestId\":\"TRANS_0406_A06\",\"creditId\":\"034201000243\",\"creditAccountType\":\"ID\",\"creditAccountName\":\"TRAN NHAT LE\",\"amount\":32987,\"creditBankBin\":\"970406\",\"transactionType\":\"fast-out\",\"creditIssueDate\":\"2022-06-02\",\"creditIssueAddress\":\"Ha Noi\",\"creditBranchCode\":\"96304004\",\"remark\":\"Thanh toan 3\"}]}";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
String timestamp = ZonedDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"))
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String signature = hmacSha512(SECRET_KEY, timestamp + ":" + bodyJson);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://open-api.tingee.vn/v1/direct-link/create-transfer"))
.header("accept", "application/json")
.header("Content-Type", "application/json")
.header("x-client-id", CLIENT_ID)
.header("x-request-timestamp", timestamp)
.header("x-signature", signature)
.method("POST", HttpRequest.BodyPublishers.ofString(bodyJson, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
private static String hmacSha512(String key, String data) throws Exception {
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) hex.append(String.format("%02x", b));
return hex.toString();
}
}
<?php
$clientId = "YOUR_CLIENT_ID";
$secretKey = "YOUR_SECRET_KEY";
$body = [
"actionType" => "INTERNAL_TRANSFER",
"action" => "INIT",
"bankBin" => "970418",
"debitAccountNumber" => "8600007007",
"currency" => "VND",
"feeMethod" => "O",
"effectiveDate" => "2026-06-04",
"remark" => "Chuyen tien nhieu nguoi",
"records" => [
[
"requestId" => "TRANS_0406_A04",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "2220366666",
"creditAccountName" => "NGUYEN VAN A",
"amount" => 32987,
"creditBankBin" => "970418",
"transactionType" => "in-bank",
"remark" => "Thanh toan 1",
],
[
"requestId" => "TRANS_0406_A05",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "6666688822",
"creditAccountName" => "NGUYEN LOC PHAT",
"amount" => 12098,
"creditBankBin" => "970406",
"transactionType" => "fast-out",
"remark" => "Thanh toan 2",
],
[
"requestId" => "TRANS_0406_A06",
"creditId" => "034201000243",
"creditAccountType" => "ID",
"creditAccountName" => "TRAN NHAT LE",
"amount" => 32987,
"creditBankBin" => "970406",
"transactionType" => "fast-out",
"creditIssueDate" => "2022-06-02",
"creditIssueAddress" => "Ha Noi",
"creditBranchCode" => "96304004",
"remark" => "Thanh toan 3",
],
],
];
// Do not escape "/" or non-ASCII characters so the JSON matches TINGEE's JSON.stringify
$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
$now = new DateTime("now", new DateTimeZone("Asia/Ho_Chi_Minh"));
$timestamp = $now->format("YmdHisv");
$signature = hash_hmac("sha512", $timestamp . ":" . $bodyJson, $secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://open-api.tingee.vn/v1/direct-link/create-transfer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $bodyJson,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"x-client-id: " . $clientId,
"x-request-timestamp: " . $timestamp,
"x-signature: " . $signature,
],
]);
$response = curl_exec($ch);
if ($response === false) {
echo "cURL Error: " . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/direct-link/create-transfer' \
--header 'accept: application/json' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'x-request-timestamp: 20240509154004003' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'Content-Type: application/json' \
--data '{
"actionType": "INTERNAL_TRANSFER",
"action": "REQUEST_APPROVAL",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"approvalNote": "Duyet gap",
"effectiveDate": "2026-06-04",
"records": [
{
"requestId": "TRANS_1006_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"remark": "Chuyen tien"
}
]
}'
import axios from "axios";
import { createHmac } from "crypto";
const CLIENT_ID = "YOUR_CLIENT_ID";
const SECRET_KEY = "YOUR_SECRET_KEY";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
function getTimestamp() {
return new Date(Date.now() + 7 * 60 * 60 * 1000)
.toISOString()
.replace(/[-:TZ.]/g, "")
.slice(0, 17);
}
async function directLinkCreateTransfer() {
const body = {
actionType: "INTERNAL_TRANSFER",
action: "REQUEST_APPROVAL",
bankBin: "970418",
debitAccountNumber: "8600007007",
currency: "VND",
feeMethod: "O",
approvalNote: "Duyet gap",
effectiveDate: "2026-06-04",
records: [
{
requestId: "TRANS_1006_A04",
creditAccountType: "ACCOUNT",
creditAccountNumber: "2220366666",
creditAccountName: "NGUYEN VAN A",
amount: 32987,
creditBankBin: "970418",
remark: "Chuyen tien",
},
],
};
const bodyJson = JSON.stringify(body);
const timestamp = getTimestamp();
const signature = createHmac("sha512", SECRET_KEY)
.update(`${timestamp}:${bodyJson}`)
.digest("hex");
const res = await axios.request({
method: "POST",
url: "https://open-api.tingee.vn/v1/direct-link/create-transfer",
data: bodyJson,
headers: {
accept: "application/json",
"Content-Type": "application/json",
"x-client-id": CLIENT_ID,
"x-request-timestamp": timestamp,
"x-signature": signature,
},
});
console.log(res.data);
}
directLinkCreateTransfer();
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
private const string ClientId = "YOUR_CLIENT_ID";
private const string SecretKey = "YOUR_SECRET_KEY";
private static readonly HttpClient Client = new HttpClient();
public static async Task Main()
{
var body = new
{
actionType = "INTERNAL_TRANSFER",
action = "REQUEST_APPROVAL",
bankBin = "970418",
debitAccountNumber = "8600007007",
currency = "VND",
feeMethod = "O",
approvalNote = "Duyet gap",
effectiveDate = "2026-06-04",
records = new object[]
{
new
{
requestId = "TRANS_1006_A04",
creditAccountType = "ACCOUNT",
creditAccountNumber = "2220366666",
creditAccountName = "NGUYEN VAN A",
amount = 32987,
creditBankBin = "970418",
remark = "Chuyen tien"
}
}
};
// Do not escape non-ASCII / special characters so the JSON matches TINGEE's JSON.stringify
var jsonOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
var timestamp = DateTime.UtcNow.AddHours(7).ToString("yyyyMMddHHmmssfff");
var signature = HmacSha512(SecretKey, $"{timestamp}:{bodyJson}");
var request = new HttpRequestMessage(HttpMethod.Post, "https://open-api.tingee.vn/v1/direct-link/create-transfer");
request.Headers.Add("accept", "application/json");
request.Headers.Add("x-client-id", ClientId);
request.Headers.Add("x-request-timestamp", timestamp);
request.Headers.Add("x-signature", signature);
request.Content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
var response = await Client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
private static string HmacSha512(string key, string message)
{
using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
return Convert.ToHexString(hash).ToLower();
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Main {
private static final String CLIENT_ID = "YOUR_CLIENT_ID";
private static final String SECRET_KEY = "YOUR_SECRET_KEY";
public static void main(String[] args) throws Exception {
// Minified JSON, same as JSON.stringify()
String bodyJson = "{\"actionType\":\"INTERNAL_TRANSFER\",\"action\":\"REQUEST_APPROVAL\",\"bankBin\":\"970418\",\"debitAccountNumber\":\"8600007007\",\"currency\":\"VND\",\"feeMethod\":\"O\",\"approvalNote\":\"Duyet gap\",\"effectiveDate\":\"2026-06-04\",\"records\":[{\"requestId\":\"TRANS_1006_A04\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"2220366666\",\"creditAccountName\":\"NGUYEN VAN A\",\"amount\":32987,\"creditBankBin\":\"970418\",\"remark\":\"Chuyen tien\"}]}";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
String timestamp = ZonedDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"))
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String signature = hmacSha512(SECRET_KEY, timestamp + ":" + bodyJson);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://open-api.tingee.vn/v1/direct-link/create-transfer"))
.header("accept", "application/json")
.header("Content-Type", "application/json")
.header("x-client-id", CLIENT_ID)
.header("x-request-timestamp", timestamp)
.header("x-signature", signature)
.method("POST", HttpRequest.BodyPublishers.ofString(bodyJson, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
private static String hmacSha512(String key, String data) throws Exception {
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) hex.append(String.format("%02x", b));
return hex.toString();
}
}
<?php
$clientId = "YOUR_CLIENT_ID";
$secretKey = "YOUR_SECRET_KEY";
$body = [
"actionType" => "INTERNAL_TRANSFER",
"action" => "REQUEST_APPROVAL",
"bankBin" => "970418",
"debitAccountNumber" => "8600007007",
"currency" => "VND",
"feeMethod" => "O",
"approvalNote" => "Duyet gap",
"effectiveDate" => "2026-06-04",
"records" => [
[
"requestId" => "TRANS_1006_A04",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "2220366666",
"creditAccountName" => "NGUYEN VAN A",
"amount" => 32987,
"creditBankBin" => "970418",
"remark" => "Chuyen tien",
],
],
];
// Do not escape "/" or non-ASCII characters so the JSON matches TINGEE's JSON.stringify
$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
$now = new DateTime("now", new DateTimeZone("Asia/Ho_Chi_Minh"));
$timestamp = $now->format("YmdHisv");
$signature = hash_hmac("sha512", $timestamp . ":" . $bodyJson, $secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://open-api.tingee.vn/v1/direct-link/create-transfer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $bodyJson,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"x-client-id: " . $clientId,
"x-request-timestamp: " . $timestamp,
"x-signature: " . $signature,
],
]);
$response = curl_exec($ch);
if ($response === false) {
echo "cURL Error: " . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/direct-link/create-transfer' \
--header 'accept: application/json' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'x-request-timestamp: 20240509154004003' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'Content-Type: application/json' \
--data '{
"actionType": "INTERNAL_TRANSFER",
"action": "REQUEST_APPROVAL",
"bankBin": "970418",
"debitAccountNumber": "8600007007",
"currency": "VND",
"feeMethod": "O",
"approvalNote": "Duyet gap",
"effectiveDate": "2026-06-04",
"remark": "Chuyen tien nhieu nguoi",
"records": [
{
"requestId": "TRANS_0406_A04",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "2220366666",
"creditAccountName": "NGUYEN VAN A",
"amount": 32987,
"creditBankBin": "970418",
"transactionType": "in-bank",
"remark": "Thanh toan 1"
},
{
"requestId": "TRANS_0406_A05",
"creditAccountType": "ACCOUNT",
"creditAccountNumber": "6666688822",
"creditAccountName": "NGUYEN LOC PHAT",
"amount": 12098,
"creditBankBin": "970406",
"transactionType": "fast-out",
"remark": "Thanh toan 2"
},
{
"requestId": "TRANS_0406_A06",
"creditId": "034201000243",
"creditAccountType": "ID",
"creditAccountName": "TRAN NHAT LE",
"amount": 32987,
"creditBankBin": "970406",
"transactionType": "fast-out",
"creditIssueDate": "2022-06-02",
"creditIssueAddress": "Ha Noi",
"creditBranchCode": "96304004",
"remark": "Thanh toan 3"
}
]
}'
import axios from "axios";
import { createHmac } from "crypto";
const CLIENT_ID = "YOUR_CLIENT_ID";
const SECRET_KEY = "YOUR_SECRET_KEY";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
function getTimestamp() {
return new Date(Date.now() + 7 * 60 * 60 * 1000)
.toISOString()
.replace(/[-:TZ.]/g, "")
.slice(0, 17);
}
async function directLinkCreateTransfer() {
const body = {
actionType: "INTERNAL_TRANSFER",
action: "REQUEST_APPROVAL",
bankBin: "970418",
debitAccountNumber: "8600007007",
currency: "VND",
feeMethod: "O",
approvalNote: "Duyet gap",
effectiveDate: "2026-06-04",
remark: "Chuyen tien nhieu nguoi",
records: [
{
requestId: "TRANS_0406_A04",
creditAccountType: "ACCOUNT",
creditAccountNumber: "2220366666",
creditAccountName: "NGUYEN VAN A",
amount: 32987,
creditBankBin: "970418",
transactionType: "in-bank",
remark: "Thanh toan 1",
},
{
requestId: "TRANS_0406_A05",
creditAccountType: "ACCOUNT",
creditAccountNumber: "6666688822",
creditAccountName: "NGUYEN LOC PHAT",
amount: 12098,
creditBankBin: "970406",
transactionType: "fast-out",
remark: "Thanh toan 2",
},
{
requestId: "TRANS_0406_A06",
creditId: "034201000243",
creditAccountType: "ID",
creditAccountName: "TRAN NHAT LE",
amount: 32987,
creditBankBin: "970406",
transactionType: "fast-out",
creditIssueDate: "2022-06-02",
creditIssueAddress: "Ha Noi",
creditBranchCode: "96304004",
remark: "Thanh toan 3",
},
],
};
const bodyJson = JSON.stringify(body);
const timestamp = getTimestamp();
const signature = createHmac("sha512", SECRET_KEY)
.update(`${timestamp}:${bodyJson}`)
.digest("hex");
const res = await axios.request({
method: "POST",
url: "https://open-api.tingee.vn/v1/direct-link/create-transfer",
data: bodyJson,
headers: {
accept: "application/json",
"Content-Type": "application/json",
"x-client-id": CLIENT_ID,
"x-request-timestamp": timestamp,
"x-signature": signature,
},
});
console.log(res.data);
}
directLinkCreateTransfer();
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
public class Program
{
private const string ClientId = "YOUR_CLIENT_ID";
private const string SecretKey = "YOUR_SECRET_KEY";
private static readonly HttpClient Client = new HttpClient();
public static async Task Main()
{
var body = new
{
actionType = "INTERNAL_TRANSFER",
action = "REQUEST_APPROVAL",
bankBin = "970418",
debitAccountNumber = "8600007007",
currency = "VND",
feeMethod = "O",
approvalNote = "Duyet gap",
effectiveDate = "2026-06-04",
remark = "Chuyen tien nhieu nguoi",
records = new object[]
{
new
{
requestId = "TRANS_0406_A04",
creditAccountType = "ACCOUNT",
creditAccountNumber = "2220366666",
creditAccountName = "NGUYEN VAN A",
amount = 32987,
creditBankBin = "970418",
transactionType = "in-bank",
remark = "Thanh toan 1"
},
new
{
requestId = "TRANS_0406_A05",
creditAccountType = "ACCOUNT",
creditAccountNumber = "6666688822",
creditAccountName = "NGUYEN LOC PHAT",
amount = 12098,
creditBankBin = "970406",
transactionType = "fast-out",
remark = "Thanh toan 2"
},
new
{
requestId = "TRANS_0406_A06",
creditId = "034201000243",
creditAccountType = "ID",
creditAccountName = "TRAN NHAT LE",
amount = 32987,
creditBankBin = "970406",
transactionType = "fast-out",
creditIssueDate = "2022-06-02",
creditIssueAddress = "Ha Noi",
creditBranchCode = "96304004",
remark = "Thanh toan 3"
}
}
};
// Do not escape non-ASCII / special characters so the JSON matches TINGEE's JSON.stringify
var jsonOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
var timestamp = DateTime.UtcNow.AddHours(7).ToString("yyyyMMddHHmmssfff");
var signature = HmacSha512(SecretKey, $"{timestamp}:{bodyJson}");
var request = new HttpRequestMessage(HttpMethod.Post, "https://open-api.tingee.vn/v1/direct-link/create-transfer");
request.Headers.Add("accept", "application/json");
request.Headers.Add("x-client-id", ClientId);
request.Headers.Add("x-request-timestamp", timestamp);
request.Headers.Add("x-signature", signature);
request.Content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
var response = await Client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
private static string HmacSha512(string key, string message)
{
using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
return Convert.ToHexString(hash).ToLower();
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class Main {
private static final String CLIENT_ID = "YOUR_CLIENT_ID";
private static final String SECRET_KEY = "YOUR_SECRET_KEY";
public static void main(String[] args) throws Exception {
// Minified JSON, same as JSON.stringify()
String bodyJson = "{\"actionType\":\"INTERNAL_TRANSFER\",\"action\":\"REQUEST_APPROVAL\",\"bankBin\":\"970418\",\"debitAccountNumber\":\"8600007007\",\"currency\":\"VND\",\"feeMethod\":\"O\",\"approvalNote\":\"Duyet gap\",\"effectiveDate\":\"2026-06-04\",\"remark\":\"Chuyen tien nhieu nguoi\",\"records\":[{\"requestId\":\"TRANS_0406_A04\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"2220366666\",\"creditAccountName\":\"NGUYEN VAN A\",\"amount\":32987,\"creditBankBin\":\"970418\",\"transactionType\":\"in-bank\",\"remark\":\"Thanh toan 1\"},{\"requestId\":\"TRANS_0406_A05\",\"creditAccountType\":\"ACCOUNT\",\"creditAccountNumber\":\"6666688822\",\"creditAccountName\":\"NGUYEN LOC PHAT\",\"amount\":12098,\"creditBankBin\":\"970406\",\"transactionType\":\"fast-out\",\"remark\":\"Thanh toan 2\"},{\"requestId\":\"TRANS_0406_A06\",\"creditId\":\"034201000243\",\"creditAccountType\":\"ID\",\"creditAccountName\":\"TRAN NHAT LE\",\"amount\":32987,\"creditBankBin\":\"970406\",\"transactionType\":\"fast-out\",\"creditIssueDate\":\"2022-06-02\",\"creditIssueAddress\":\"Ha Noi\",\"creditBranchCode\":\"96304004\",\"remark\":\"Thanh toan 3\"}]}";
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
String timestamp = ZonedDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"))
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String signature = hmacSha512(SECRET_KEY, timestamp + ":" + bodyJson);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://open-api.tingee.vn/v1/direct-link/create-transfer"))
.header("accept", "application/json")
.header("Content-Type", "application/json")
.header("x-client-id", CLIENT_ID)
.header("x-request-timestamp", timestamp)
.header("x-signature", signature)
.method("POST", HttpRequest.BodyPublishers.ofString(bodyJson, StandardCharsets.UTF_8))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
private static String hmacSha512(String key, String data) throws Exception {
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) hex.append(String.format("%02x", b));
return hex.toString();
}
}
<?php
$clientId = "YOUR_CLIENT_ID";
$secretKey = "YOUR_SECRET_KEY";
$body = [
"actionType" => "INTERNAL_TRANSFER",
"action" => "REQUEST_APPROVAL",
"bankBin" => "970418",
"debitAccountNumber" => "8600007007",
"currency" => "VND",
"feeMethod" => "O",
"approvalNote" => "Duyet gap",
"effectiveDate" => "2026-06-04",
"remark" => "Chuyen tien nhieu nguoi",
"records" => [
[
"requestId" => "TRANS_0406_A04",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "2220366666",
"creditAccountName" => "NGUYEN VAN A",
"amount" => 32987,
"creditBankBin" => "970418",
"transactionType" => "in-bank",
"remark" => "Thanh toan 1",
],
[
"requestId" => "TRANS_0406_A05",
"creditAccountType" => "ACCOUNT",
"creditAccountNumber" => "6666688822",
"creditAccountName" => "NGUYEN LOC PHAT",
"amount" => 12098,
"creditBankBin" => "970406",
"transactionType" => "fast-out",
"remark" => "Thanh toan 2",
],
[
"requestId" => "TRANS_0406_A06",
"creditId" => "034201000243",
"creditAccountType" => "ID",
"creditAccountName" => "TRAN NHAT LE",
"amount" => 32987,
"creditBankBin" => "970406",
"transactionType" => "fast-out",
"creditIssueDate" => "2022-06-02",
"creditIssueAddress" => "Ha Noi",
"creditBranchCode" => "96304004",
"remark" => "Thanh toan 3",
],
],
];
// Do not escape "/" or non-ASCII characters so the JSON matches TINGEE's JSON.stringify
$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Timestamp in UTC+7, format yyyyMMddHHmmssSSS
$now = new DateTime("now", new DateTimeZone("Asia/Ho_Chi_Minh"));
$timestamp = $now->format("YmdHisv");
$signature = hash_hmac("sha512", $timestamp . ":" . $bodyJson, $secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://open-api.tingee.vn/v1/direct-link/create-transfer",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $bodyJson,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"x-client-id: " . $clientId,
"x-request-timestamp: " . $timestamp,
"x-signature: " . $signature,
],
]);
$response = curl_exec($ch);
if ($response === false) {
echo "cURL Error: " . curl_error($ch);
} else {
echo $response;
}
curl_close($ch);
Sample Response
Depending on the action parameter (save as draft or submit for approval) and the number of transactions (single or batch), the API returns the structure for one of the 4 cases below:
- INIT (Single)
- INIT (Batch)
- REQUEST_APPROVAL (Single)
- REQUEST_APPROVAL (Batch)
Response when saving a draft (action="INIT") for a single transaction.
{
"code": "00",
"message": "Success",
"data": {
"status": "SUCCESS",
"totalRecords": 1,
"validRecords": 1,
"invalidRecords": 0,
"requireAuth": false,
"transAuth": null,
"records": [
{
"requestId": "TRANS_1006_A04",
"status": "INIT",
"transactionId": "PM0226061000074420",
"transactionCode": "PM02",
"message": null,
"feeTotal": 11000
}
]
}
}
Response when saving a draft (action="INIT") for a batch of multiple transactions.
{
"code": "00",
"message": "Success",
"data": {
"status": "SUCCESS",
"batchId": "0000009b-c09c-403b-b2bc-19a35a6845a4",
"totalRecords": 3,
"validRecords": 3,
"invalidRecords": 0,
"requireAuth": false,
"transAuth": null,
"records": [
{
"requestId": "TRANS_2026_0047",
"status": "INIT",
"transactionId": "PM0226050800069511",
"transactionCode": "PM02",
"message": null,
"feeTotal": 22000
},
{
"requestId": "TRANS_2026_0048",
"status": "INIT",
"transactionId": "PM1126050800069512",
"transactionCode": "PM11",
"message": null,
"feeTotal": 11000
},
{
"requestId": "TRANS_2026_0049",
"status": "INIT",
"transactionId": "PM1326050800069513",
"transactionCode": "PM13",
"message": null,
"feeTotal": 5500
}
]
}
}
Response when submitting a single transaction for approval directly (action="REQUEST_APPROVAL").
{
"code": "00",
"message": "Success",
"data": {
"status": "PENDING_CONFIRMATION",
"confirmId": "TXNKEY_INIT_PM13_25607354makerotv_2827594e-037d-434b-b534-b1ff52adad4a",
"totalRecords": 1,
"validRecords": 1,
"invalidRecords": 0,
"requireAuth": true,
"transAuth": {
"authType": "SMARTOTP",
"expTime": 120,
"qrData": "OTkwMDVCMDUwMDMyMTc4MDU1ODgzOTU2MS01MGQzNDM3Ni1iMGVlLTQ2NTEtOWMxMC1iNDMxZDYwYTI0M2QwNjAwMDQ3OTczMjAwMDEzQklEVklCQU5LX1RSQU5TX09UUA=="
},
"records": [
{
"requestId": "TRANS_0406_A08",
"status": "REQUEST_APPROVAL",
"transactionId": "PM1326050800069513",
"transactionCode": "PM13",
"message": null,
"feeTotal": 11000
}
]
}
}
Response when submitting a batch of multiple transactions for approval directly (action="REQUEST_APPROVAL").
{
"code": "00",
"message": "Success",
"data": {
"status": "PENDING_CONFIRMATION",
"confirmId": "TXNKEY_APPROVAL_25607354makerotv_a8993883-d5fe-4ced-a0c0-20cff5b5120b",
"batchId": "2667c208-a5ab-4c9c-af4d-cbd4de24b817",
"totalRecords": 3,
"validRecords": 3,
"invalidRecords": 0,
"requireAuth": true,
"transAuth": {
"authType": "SMARTOTP",
"expTime": 120,
"qrData": "OTkwMDVCMDUwMDMyMTc4MTE0MjI4NDkwNS1kYjdjZWU3NC1hNTdjLTQxMjItODljZi1jZmEyYWNjMDkyZjgwNjAwMDQ3OTczMjAwMDEzQklEVklCQU5LX1RSQU5TX09UUA=="
},
"records": []
}
}
Response data structure
| Field | Type | Description |
|---|---|---|
status | string | Disbursement order status: - SUCCESS: Draft saved successfully (action = INIT) - PENDING_CONFIRMATION: Approval request created, awaiting OTP confirmation via the Confirm payment order API with confirmId - PARTIALLY_VALID: Draft saved successfully but the batch contains invalid records (SALARY / BILL_PAYMENT only) - REQUIRES_CONFIRMATION: BIDV returned a warning that must be confirmed before continuing (SALARY / BILL_PAYMENT only); the warning text is in message. Resend exactly the same payload within 5 minutes to confirm and continue creating the order. |
message | string | Warning text from BIDV (only returned when status = REQUIRES_CONFIRMATION). |
batchId | string | Transaction batch ID (only returned when creating an INTERNAL_TRANSFER batch order or a SALARY / BILL_PAYMENT order). Used for the Download batch result file API and BATCH_UPLOAD_INQUIRY queries. |
confirmId | string | Transaction confirmation key (only returned when submitting for approval with REQUEST_APPROVAL). |
transactionId | string | Batch-level transaction ID (SALARY / BILL_PAYMENT only) — used for the submit-for-approval, approve, reject, delete and detail inquiry APIs. |
transactionCode | string | Bank-side transaction type code (SALARY / BILL_PAYMENT only). |
totalRecords | number | Total number of transactions. |
validRecords | number | Number of valid transactions. |
invalidRecords | number | Number of invalid transactions. |
requireAuth | boolean | Whether additional transaction authentication is required (e.g. SmartOTP) (INTERNAL_TRANSFER only). |
transAuth | object | Authentication configuration (set when additional authentication is needed, otherwise null). |
records | array | Detailed result of each transaction (for a batch order submitted with REQUEST_APPROVAL, this array is empty because the individual child orders have no processing result yet). |
For INTERNAL_TRANSFER batch orders and SALARY / BILL_PAYMENT orders, if BIDV checks the batch file and finds invalid records, the API returns code = "400" with data containing batchId, validRecords and invalidRecords. Use Query transactions with inquiryType = BATCH_UPLOAD_INQUIRY, the matching batchId and status = INVALID to see the error for each record.
data.transAuth details (if additional authentication is required)
| Field | Type | Description |
|---|---|---|
authType | string | Authentication method (e.g. SMARTOTP). |
expTime | number | Validity period of the QR code (in seconds). |
qrData | string | Data string used to render the QR code image. Scan it in the bank app to get the OTP. |
Items in data.records
| Field | Type | Description |
|---|---|---|
requestId | string | The transaction reference you sent. |
status | string | Transaction status returned by BIDV; by default INIT (draft) or REQUEST_APPROVAL (submitted for approval). |
transactionId | string | Transaction ID in the BIDV system (INTERNAL_TRANSFER only) — used for the submit-for-approval, approve, reject, delete and TRANSFER_DETAIL inquiry APIs (the id field). |
transactionSubId | string | Child transaction ID within the batch (SALARY / BILL_PAYMENT only). |
transactionCode | string | Bank-side transaction type code (INTERNAL_TRANSFER only). |
message | string | Error message (if any). |
feeTotal | number | Total transaction fee. |
When you submit transactions for approval and the system returns requireAuth: true along with transAuth.qrData, follow these steps to get the OTP:
- Convert the string in
qrDatainto a QR code image. - Open the BIDV Direct app on a device (that has been granted approval rights).
- Use the app's QR scanner to scan the QR image you just generated.
- Carefully check the transaction details on the app screen and confirm with your BIDV Direct PIN.
- After you confirm the PIN, a SmartOTP is displayed on the screen.
- Pass this SmartOTP in the
otpparameter of the Confirm transfer order API to complete the transaction.
Common error codes
| Code | Description | How to handle |
|---|---|---|
1112 | The transaction list (records) is empty | Pass at least one record in records, then resend. |
1077 | The BIDV authorization session of the maker (Maker) has expired or has not been granted | Call Get authorization URL with role = Maker to re-authorize, then create the transaction again. |
1021 | The bank is not supported for the Maker/Checker flow | Check bankBin; the Maker/Checker flow applies to BIDV (970418). |
90, 91, 92, 97 | Request authentication error (timestamp, client-id, signature) | See System error codes. |
Others | Other errors | See Error codes. |