Tạo tài khoản ảo (VA)
API này dùng để tạo mới tài khoản ảo (Virtual Account - VA) cho Merchant, cho phép nhận thông báo biến động số dư và quản lý dòng tiền tách biệt.
Trải nghiệm toàn bộ quy trình liên kết tài khoản và xác thực OTP với dữ liệu giả lập.
API khởi tạo yêu cầu tạo hoặc liên kết tài khoản ảo với ngân hàng. Kết quả trả về confirmId cần được dùng cho bước xác nhận tiếp theo.
Header Request
| Header | Bắt buộc | Mô tả |
|---|---|---|
Content-Type | ✓ | application/json |
x-client-id | ✓ | Mã định danh của đối tác do TINGEE cung cấp. |
x-signature | ✓ | Chữ ký xác thực HMAC SHA512. Xem thêm tại Cách sinh chữ ký. |
x-request-timestamp | ✓ | Thời gian gửi request (format: yyyyMMddHHmmssSSS, múi giờ UTC+7) |
Đối với ngân hàng VIB (bankBin: "970441"), khách hàng bắt buộc phải đăng ký nhận loa trên VIB iBusiness trước khi gọi API tạo VA. Xem chi tiết các bước tại Điều kiện liên kết tài khoản VIB hoặc Tab VIB ở phần Mẫu Request Body.
Body Parameter
1. Thông tin Ngân hàng & Tài khoản chung
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
bankBin | string | ✓ | Mã BIN ngân hàng (6 chữ số). Xem tại Danh sách ngân hàng hỗ trợ. Ví dụ: 970418 (BIDV), 970436 (VCB), 970422 (MBB), 970415 (VietinBank)... |
accountType | string | ~ | Loại tài khoản (BankAccountTypeEnum):- personal-account: Tài khoản cá nhân.- business-account: Tài khoản doanh nghiệp.- business-household-account: Tài khoản hộ kinh doanh.Bắt buộc với tất cả ngân hàng, trừ BAOKIM. |
accountNumber | string | ~ | Số tài khoản ngân hàng gốc cần liên kết. Không bắt buộc đối với: TPBank, VCB, MSB và BAOKIM. |
accountName | string | ~ | Tên chủ tài khoản ngân hàng (viết hoa không dấu). Không bắt buộc đối với TPBank, PGBank, BAOKIM và tài khoản Doanh nghiệp của BIDV, OCB, VIB, SHINHAN, VietinBank (CTG). |
identity | string | ~ | Giấy tờ tùy thân của khách hàng (CMND/CCCD hoặc Mã số thuế). Không áp dụng với VCB, ACB và tài khoản Doanh nghiệp. |
mobile | string | ~ | Số điện thoại đăng ký nhận OTP / liên kết. Bắt buộc đối với Vietcombank (VCB) tài khoản Cá nhân. Không bắt buộc với: VPBank, VCB, CTG, VIB, BAOKIM, TPBank và tài khoản Doanh nghiệp của BIDV, Shinhan, OCB. |
isNotifyAccountNumber | boolean | ✕ | Loại liên kết: - false (mặc định): Tạo tài khoản ảo (Virtual Account).- true: Liên kết số tài khoản gốc (nhận biến động số dư STK gốc).Chỉ áp dụng với các ngân hàng hỗ trợ. Xem chi tiết tại Lưu ý quan trọng. |
transactionType | string | ✕ | Loại giao dịch đăng ký (TransactionTypeEnum):- credit: Giao dịch ghi có (nhận tiền - mặc định).- debit: Giao dịch ghi nợ (chỉ hỗ trợ duy nhất ngân hàng ACB). |
appType | string | ✕ | Loại ứng dụng tích hợp. Mặc định là baas. |
2. Thông tin Virtual Account & Shop
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
vaPrefix | string | ✕ | Tiền tố tài khoản ảo (VA). |
vaSuffix | string | ~ | Hậu tố tài khoản ảo (VA). Bắt buộc đối với tài khoản Doanh nghiệp của BIDV và VietinBank (CTG) (dùng để ghép số VA ${vaPrefix}${vaSuffix}); hoặc Doanh nghiệp OCB (khi isNotifyAccountNumber = false). |
merchantName | string | ~ | Tên hiển thị khi thanh toán (chủ tài khoản VA). Chỉ áp dụng đối với ngân hàng BIDV và VietinBank (CTG). Tên bắt buộc phải bắt đầu bằng tên Doanh nghiệp đã đăng ký. |
merchantId | number | ~ | ID của Merchant con cần tạo VA (Bắt buộc nếu kết nối bằng tài khoản Master Merchant). |
shopId | number | ✕ | ID cửa hàng muốn gán VA vào. Nếu truyền tham số này, hệ thống sẽ gán VA được tạo vào cửa hàng tương ứng. Nếu để trống, hệ thống sẽ tự động tạo một cửa hàng mới khi tạo VA và gán VA vào cửa hàng mới đó. (ID cửa hàng sẽ được trả về trong response). |
merchantAddress | string | ✕ | Địa chỉ của cửa hàng/merchant (dùng khi tự động tạo cửa hàng mới). |
name | string | ✕ | Tên dòng tiền / tên định danh dòng tiền phục vụ quản lý nội bộ. |
taxCode | string | ✕ | Mã số thuế của doanh nghiệp / hộ kinh doanh. |
3. Tham số chuyên biệt theo từng Ngân hàng
| Ngân hàng | Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
| Vietcombank (VCB) & TPBank | webhookUrl | string | ~ | URL nhận thông báo kết quả đăng ký/hủy tài khoản từ ngân hàng. Bắt buộc đối với TPBank (mọi loại tài khoản) hoặc Vietcombank (Cá nhân, Hộ kinh doanh). Xem chi tiết cấu trúc dữ liệu tại Webhook thông báo trạng thái liên kết tài khoản. |
| TPBank (TPB) | requestId | string | ~ | Mã định danh yêu cầu duy nhất từ phía đối tác. Bắt buộc đối với TPBank. |
| ACB | acbUserId | string | ~ | User ID đăng nhập trên hệ thống ACB Online / Biz. Bắt buộc đối với tài khoản ACB Doanh nghiệp hoặc Hộ kinh doanh. |
| Bảo Kim (BAOKIM) | walletId | string | ~ | ID Ví điện tử Bảo Kim muốn tạo STK ảo. Bắt buộc khi sử dụng bankBin = BAOKIM. |
isNotifyAccountNumber = true)- Các ngân hàng hỗ trợ liên kết STK gốc:
- ACB, TPBank: Hỗ trợ mọi loại tài khoản (Cá nhân, HKD, Doanh nghiệp). (Lưu ý: TPBank chỉ Doanh nghiệp mới có VA, Cá nhân và HKD không có VA).
- VPBank: Hỗ trợ tài khoản Doanh nghiệp và Cá nhân.
- OCB: Hỗ trợ tài khoản Doanh nghiệp và Hộ kinh doanh.
- VietinBank: Hỗ trợ tài khoản Cá nhân và Hộ kinh doanh.
- PGBank, Co-opBank: Chỉ hỗ trợ liên kết STK gốc (không có VA, hệ thống tự động xử lý).
- Cơ chế nhận Webhook giao dịch theo loại tài khoản:
- Với tài khoản liên kết STK gốc (
isNotifyAccountNumber = true): Chuyển tiền vào STK gốc mới phát sinh Webhook từ Tingee. - Với tài khoản không hỗ trợ liên kết gốc (chỉ hỗ trợ VA,
isNotifyAccountNumber = false): Bắt buộc chuyển tiền vào số tài khoản ảo (VA). Nếu chuyển vào STK gốc, phía ngân hàng sẽ không gửi giao dịch về Tingee → Tingee không nhận được GD từ bank → Không có Webhook.
- Với tài khoản liên kết STK gốc (
- Đối với các ngân hàng còn lại, hệ thống mặc định chỉ hỗ trợ tạo tài khoản ảo (VA), vui lòng để
isNotifyAccountNumber = falsehoặc không truyền. - Xem chi tiết tại Bảng hỗ trợ liên kết STK gốc.
Mẫu Request Body theo từng Ngân hàng
- Cá nhân thông dụng (MBB, OCB, Sacombank...)
- BIDV & VietinBank (Doanh nghiệp)
- Vietcombank (Cá nhân)
- TPBank
- ACB (Doanh nghiệp / Hộ KD)
- Bảo Kim
- VIB
Dùng cho liên kết tài khoản cá nhân của các ngân hàng tiêu chuẩn (MB Bank, Sacombank, OCB, Shinhan, BIDV cá nhân...):
{
"bankBin": "970422",
"accountType": "personal-account",
"accountNumber": "0935926988",
"accountName": "NGUYEN THI HUYEN",
"identity": "040191014068",
"mobile": "0123456789",
"isNotifyAccountNumber": false
}
Áp dụng cho tài khoản Doanh nghiệp của BIDV (970418) và VietinBank (970415). Hệ thống sẽ ghép số VA theo cấu trúc vaPrefix + vaSuffix:
{
"bankBin": "970418",
"accountType": "business-account",
"accountNumber": "1234567890",
"vaPrefix": "TINGEE",
"vaSuffix": "8888",
"merchantName": "CONG TY TNHH ABC CUA HANG 1",
"isNotifyAccountNumber": false
}
Lưu ý:
merchantNamebắt buộc phải bắt đầu bằng đúng tên Doanh nghiệp đã đăng ký với ngân hàng.
Áp dụng cho tài khoản Cá nhân Vietcombank (970436). Khách hàng sẽ mở App VCB Digibank qua Deep Link để hoàn tất xác thực liên kết:
{
"bankBin": "970436",
"accountType": "personal-account",
"mobile": "0935926988",
"appType": "baas",
"webhookUrl": "https://your-domain.com/webhook/vcb-link",
"isNotifyAccountNumber": false
}
Áp dụng cho ngân hàng TPBank (970423). Đối tác cần truyền requestId định danh duy nhất và webhookUrl để nhận kết quả liên kết từ TPBank Biz:
{
"bankBin": "970423",
"accountType": "personal-account",
"requestId": "REQ_20261008_0001",
"webhookUrl": "https://your-domain.com/webhook/tpbank-link",
"isNotifyAccountNumber": false
}
Áp dụng khi tạo tài khoản Doanh nghiệp hoặc Hộ kinh doanh tại ACB (970416):
{
"bankBin": "970416",
"accountType": "business-account",
"accountNumber": "88889999",
"accountName": "CONG TY CP CONG NGHE XYZ",
"acbUserId": "ACB_USER_LOGIN_ID",
"isNotifyAccountNumber": false
}
Áp dụng khi liên kết ví điện tử Bảo Kim:
{
"bankBin": "BAOKIM",
"walletId": "WALLET_BAOKIM_123456",
"isNotifyAccountNumber": false
}
Khách hàng bắt buộc phải hoàn thành các bước sau trên hệ thống VIB trước khi gọi API tạo VA:
- Đăng ký tài khoản trên app MyVIB (nếu chưa có).
- Vào app MyVIB đăng ký gói iBusiness.
- Sử dụng tài khoản MyVIB đăng nhập vào VIB iBusiness và click Đăng ký nhận loa.
Mẫu request body khi tạo VA cho VIB (970441):
{
"bankBin": "970441",
"accountType": "personal-account",
"accountNumber": "0123456789",
"accountName": "NGUYEN VAN A",
"identity": "001200012345",
"isNotifyAccountNumber": false
}
Ví dụ mã nguồn
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/create-va' \
--header 'accept: application/json' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'x-request-timestamp: 20250723142001111' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{
"bankBin": "970418",
"accountType": "personal-account",
"accountNumber": "0935926988",
"accountName": "NGUYEN THI HUYEN",
"identity": "040191014068",
"mobile": "0123456789",
"isNotifyAccountNumber": false
}'
import axios from "axios";
import { createHmac } from "crypto";
import { format } from 'date-fns';
async function createVA() {
const body = {
bankBin: '970418',
accountType: 'personal-account',
accountNumber: '0935926988',
accountName: 'NGUYEN THI HUYEN',
identity: '040191014068',
mobile: '0123456789',
isNotifyAccountNumber: false,
};
const timestamp = format(new Date(), "yyyyMMddHHmmssSSS");
const secretKey = "YOUR_SECRET_KEY";
const message = `${timestamp}:${JSON.stringify(body)}`;
const signature = createHmac('sha512', secretKey).update(message).digest('hex');
const res = await axios.post('https://open-api.tingee.vn/v1/create-va', body, {
headers: {
accept: 'application/json',
'x-signature': signature,
'x-request-timestamp': timestamp,
'x-client-id': 'YOUR_CLIENT_ID',
'Content-Type': 'application/json',
},
});
console.log(res.data);
}
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Security.Cryptography;
using System.Threading.Tasks;
public class CreateVAExample
{
private static readonly HttpClient client = new HttpClient();
public static async Task Main()
{
var body = new {
bankBin = "970418",
accountType = "personal-account",
accountNumber = "0935926988",
accountName = "NGUYEN THI HUYEN",
identity = "040191014068",
mobile = "0123456789",
isNotifyAccountNumber = false
};
var timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff");
var secretKey = "YOUR_SECRET_KEY";
var bodyJson = JsonSerializer.Serialize(body);
var message = $"{timestamp}:{bodyJson}";
var signature = CreateHmacSha512(secretKey, message);
var request = new HttpRequestMessage(HttpMethod.Post, "https://open-api.tingee.vn/v1/create-va");
request.Headers.Add("x-signature", signature);
request.Headers.Add("x-request-timestamp", timestamp);
request.Headers.Add("x-client-id", "YOUR_CLIENT_ID");
request.Content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
private static string CreateHmacSha512(string key, string message)
{
using var hmac = new HMACSHA512(Encoding.UTF8.GetBytes(key));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
return BitConverter.ToString(hash).Replace("-", "").ToLower();
}
}
import java.net.http.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class CreateVA {
public static void main(String[] args) throws Exception {
String bodyJson = "{\"bankBin\":\"970418\",\"accountType\":\"personal-account\",\"accountNumber\":\"0935926988\",\"accountName\":\"NGUYEN THI HUYEN\",\"identity\":\"040191014068\",\"mobile\":\"0123456789\",\"isNotifyAccountNumber\":false}";
String secretKey = "YOUR_SECRET_KEY";
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String message = timestamp + ":" + bodyJson;
String signature = hmacSha512(secretKey, message);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://open-api.tingee.vn/v1/create-va"))
.header("accept", "application/json")
.header("x-signature", signature)
.header("x-request-timestamp", timestamp)
.header("x-client-id", "YOUR_CLIENT_ID")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(bodyJson))
.build();
HttpResponse<String> response = client.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");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return toHex(hash);
}
private static String toHex(byte[] bytes) {
StringBuilder hex = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
hex.append(String.format("%02x", b));
}
return hex.toString();
}
}
function createVA() {
$body = [
"bankBin" => "970418",
"accountType" => "personal-account",
"accountNumber" => "0935926988",
"accountName" => "NGUYEN THI HUYEN",
"identity" => "040191014068",
"mobile" => "0123456789",
"isNotifyAccountNumber" => false
];
$jsonBody = json_encode($body);
$timestamp = date("YmdHis") . substr((string)microtime(true), -3);
$secretKey = "YOUR_SECRET_KEY";
$message = $timestamp . ":" . $jsonBody;
$signature = hash_hmac("sha512", $message, $secretKey);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://open-api.tingee.vn/v1/create-va",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $jsonBody,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Content-Type: application/json",
"x-client-id: YOUR_CLIENT_ID",
"x-request-timestamp: " . $timestamp,
"x-signature: " . $signature
]
]);
$response = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
if ($err) {
echo "cURL Error: " . $err;
} else {
echo $response;
}
}
Response mẫu
{
"code": "00",
"message": "Success",
"data": {
"confirmId": "VA_CONFIRM_123456",
"shopId": 109876,
"authorizeLink": "https://ebank.tpb.vn/biz/authorize?token=...",
"deepLink": "tingeevcbmerchant://vcb-link-account?token=...",
"otpMethod": "SMSTTT"
}
}
| Trường | Kiểu | Mô tả |
|---|---|---|
code | string | Mã kết quả (00 = Thành công). |
message | string | Thông điệp phản hồi. |
data.confirmId | string | Mã xác nhận cần dùng cho API confirm-va. |
data.shopId | number | ID cửa hàng (trả về khi hệ thống tạo mới hoặc gán vào cửa hàng hiện tại). |
data.authorizeLink | string | Link đăng nhập web TPBank BIZ (chỉ áp dụng trong trường hợp liên kết tài khoản ngân hàng TPBank). |
data.deepLink | string | Link mở ứng dụng Vietcombank Digibank (chỉ áp dụng đối với Vietcombank). |
data.otpMethod | string | Phương thức xác thực OTP do ngân hàng quy định: SMSTTT, SmartOTP, mCode (chỉ áp dụng với Sacombank). |
Mã lỗi thường gặp
| Code | Mô tả | Hướng xử lý |
|---|---|---|
90 | Sai format timestamp | Kiểm tra format yyyyMMddHHmmssSSS. |
91 | Request quá hạn | Kiểm tra thời gian gửi request. |
97 | Sai chữ ký | Kiểm tra lại Secret Key và logic tạo Signature. |
Others | Lỗi khác | Xem Danh sách mã lỗi. |