Tạo QR Code động Tingee (Dynamic QR)
API này cho phép tạo mã QR động cho từng giao dịch cụ thể, hỗ trợ thanh toán một lần hoặc nhiều lần tùy theo cấu hình.
POST
URLhttps://uat-open-api.tingee.vn/v1/generate-dynamic-qr
API tạo mã QR động cho từng giao dịch. Kết quả trả về bao gồm chuỗi mã QR và thông tin hóa đơn trên hệ thống.
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) |
Body Parameter
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
merchantId | number | ✕ | ID của Merchant (Bắt buộc nếu kết nối bằng tài khoản Master Merchant). |
vaAccountNumber | string | ✓ | Số tài khoản định danh (VA). |
qrCodeType | string | ✓ | Loại QR: dynamic-one-time-payment hoặc dynamic-recurring-payment. |
bankBin | string | ✓ | Mã BIN ngân hàng. Xem tại Danh sách ngân hàng hỗ trợ. |
amount | number | ✓ | Số tiền cần thanh toán. |
purpose | string | ✕ | Nội dung thanh toán. |
expireInMinute | number | ✓ | Thời gian hết hạn QR động (phút). |
extraInfo | string | ✕ | Thông tin bổ sung. |
Ví dụ mã nguồn
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://uat-open-api.tingee.vn/v1/generate-dynamic-qr' \
--header 'accept: application/json' \
--header 'x-signature: YOUR_SIGNATURE' \
--header 'x-request-timestamp: 20251110175110111' \
--header 'x-client-id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{
"vaAccountNumber": "V1T199988811",
"qrCodeType": "dynamic-one-time-payment",
"bankBin": "970418",
"amount": 500000,
"purpose": "Thanh toan cho hoa don HD2918732312"
}'
import axios from "axios";
import { createHmac } from "crypto";
import { format } from 'date-fns';
async function generateDynamicQR() {
const body = {
vaAccountNumber: "V1T199988811",
qrCodeType: "dynamic-one-time-payment",
bankBin: "970418",
amount: 500000,
purpose: "Thanh toan cho hoa don HD2918732312"
};
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://uat-open-api.tingee.vn/v1/generate-dynamic-qr",
body,
{
headers: {
accept: "application/json",
"x-client-id": "YOUR_CLIENT_ID",
"x-request-timestamp": timestamp,
"x-signature": signature,
"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 GenerateDynamicQRExample
{
private static readonly HttpClient client = new HttpClient();
public static async Task Main()
{
var body = new {
vaAccountNumber = "V1T199988811",
qrCodeType = "dynamic-one-time-payment",
bankBin = "970418",
amount = 500000,
purpose = "Thanh toan cho hoa don HD2918732312"
};
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://uat-open-api.tingee.vn/v1/generate-dynamic-qr");
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 GenerateDynamicQR {
public static void main(String[] args) throws Exception {
String bodyJson = "{\"vaAccountNumber\":\"V1T199988811\",\"qrCodeType\":\"dynamic-one-time-payment\",\"bankBin\":\"970418\",\"amount\":500000,\"purpose\":\"Thanh toan cho hoa don HD2918732312\"}";
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://uat-open-api.tingee.vn/v1/generate-dynamic-qr"))
.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 generateDynamicQR() {
$body = [
"vaAccountNumber" => "V1T199988811",
"qrCodeType" => "dynamic-one-time-payment",
"bankBin" => "970418",
"amount" => 500000,
"purpose" => "Thanh toan cho hoa don HD2918732312"
];
$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://uat-open-api.tingee.vn/v1/generate-dynamic-qr",
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": {
"qrCode": "00020101021238540010A00000072701240006970418011088880935920208QRIBIDV2530370454085000005802VN... ",
"qrAccount": "88880935926988",
"billId": "QR_BILL_202507231420"
}
}
| 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.qrCode | string | Chuỗi nội dung của mã QR (để dùng thư viện render hoặc link ảnh). |
data.qrAccount | string | Số tài khoản nhận tiền tương ứng. |
data.billId | string | Mã vận đơn/hóa đơn tương ứng trên hệ thống Tingee. |
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. |