Register for debit notifications
Use this API to register for notifications of debit transactions (money out) on an ACB original account number. Once registration succeeds, every time money is deducted from the account, TINGEE sends a webhook to the partner's system.
Scope
- Only ACB (
bankBin = "970416") is supported, for personal, household business and business accounts. - The API registers on the original account number; it does not create a virtual account (VA).
- If the account number is already registered for credit notifications (created with Create/Link account number with
isNotifyAccountNumber = true), the system switches the registration to receive both credit and debit notifications.
Process
- Call this API to send the registration request. ACB sends an OTP to the account holder's
mobilephone number, and the result returns aconfirmId. - Call the Confirm account number API with the
confirmIdandotpNumberto complete it. TheconfirmIdis valid for 4 minutes.
POST
URLhttps://open-api.tingee.vn/v1/create-debit
Start a request to register for debit notifications on an ACB account. The result returns a confirmId used for the OTP confirmation step.
Header Request
| Header | Required | Description |
|---|---|---|
Content-Type | ✓ | application/json |
x-client-id | ✓ | Partner identifier issued by TINGEE. |
x-signature | ✓ | HMAC SHA512 authentication signature. See How to generate the signature. |
x-request-timestamp | ✓ | Time the request is sent (format: yyyyMMddHHmmssSSS, UTC+7) |
Body Parameter
| Field | Type | Required | Description |
|---|---|---|---|
bankBin | string | ✓ | Always 970416 (ACB). |
accountType | string | ✓ | Account type: personal-account, business-account, business-household-account. |
accountNumber | string | ✓ | ACB account number to register. |
accountName | string | ✓ | Account holder name (uppercase, without diacritics). |
mobile | string | ✓ | Phone number registered with ACB, used to receive the OTP. Format: 10 digits, starting with 0. |
acbUserId | string | ~ | ACB Online / Biz login user ID. Required for business and household business accounts. |
merchantId | number | ~ | Merchant ID (required if you connect with a Master Merchant account). |
shopId | number | ✕ | ID of the shop to assign the account to. If left empty, the system creates a new shop on confirmation. |
name | string | ✕ | Account nickname. Default: ACB - {accountNumber} - Ghi nợ. |
merchantName | string | ✕ | Shop name (used when the system creates a new shop). |
merchantAddress | string | ✕ | Shop address (used when the system creates a new shop). |
Code samples
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/create-debit' \
--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 '{
"bankBin": "970416",
"accountType": "personal-account",
"accountNumber": "12345678",
"accountName": "NGUYEN VAN A",
"mobile": "0935926988"
}'
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 createDebit() {
const body = {
bankBin: "970416",
accountType: "personal-account",
accountNumber: "12345678",
accountName: "NGUYEN VAN A",
mobile: "0935926988",
};
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/create-debit",
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);
}
createDebit();
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
{
bankBin = "970416",
accountType = "personal-account",
accountNumber = "12345678",
accountName = "NGUYEN VAN A",
mobile = "0935926988"
};
// 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/create-debit");
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 = "{\"bankBin\":\"970416\",\"accountType\":\"personal-account\",\"accountNumber\":\"12345678\",\"accountName\":\"NGUYEN VAN A\",\"mobile\":\"0935926988\"}";
// 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/create-debit"))
.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 = [
"bankBin" => "970416",
"accountType" => "personal-account",
"accountNumber" => "12345678",
"accountName" => "NGUYEN VAN A",
"mobile" => "0935926988",
];
// 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/create-debit",
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
{
"code": "00",
"message": "Success",
"data": {
"confirmId": "c2a8f3e0-4b1d-4e0a-9a51-7d2f0e6b9c11"
}
}
| Field | Type | Description |
|---|---|---|
code | string | Result code (00 = success). |
message | string | Response message. |
data.confirmId | string | Confirmation ID, used to call the Confirm account number API within 4 minutes. |
Common error codes
| Code | Description | How to handle |
|---|---|---|
1059 | The bank does not support this operation | This API only applies to ACB. |
1048 | Account number already registered | The account is already registered for debit notifications. |
1022 | Account already exists | The account is already registered for both credit and debit notifications. |
1031, 1085 | Shop does not exist or is inactive | Check shopId, or leave it empty so the system creates a shop. |
1037, 1103 | The shop's TingeeBox device does not support this bank | Choose another shop that matches the device configuration. |
1095, 1096 | Master Merchant merchantId error | Pass a merchantId that belongs to the Master Merchant calling the API. |
400 | Invalid data or error from ACB | message describes the details (e.g. the phone number does not match the information at ACB). |
90, 91, 92, 97 | Request authentication error (timestamp, client-id, signature) | See System error codes. |
Others | Other errors | See Error codes. |