Show a QR code on the device
This API makes a TingeeBox device show a payment QR code on its screen. Choose the QR type to show:
- 🔄 Dynamic QR
- 📄 Static QR
POST
URLhttps://open-api.tingee.vn/v1/device/show-dynamic-qr-code
Send a dynamic QR code to the TINGEEBOX device to show to customers.
Note
Some banks let customers edit the amount themselves when scanning a dynamic QR. See how to verify transactions in Important notes — Dynamic QR transactions.
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 |
|---|---|---|---|
merchantId | number | ~ | Merchant ID (Required if you connect with a Master Merchant account). |
uuid | string | ~ | Device code. Pass uuid, or the trio bankBin (or bankName) + vaAccountNumber + deviceType so the system finds the devices attached to the account (via the account or the shop that contains it). When uuid is passed, vaAccountNumber, bankBin, bankName and deviceType are ignored. Currently only TingeeBox 6XS and TingeeBox 3LS devices can show QR codes. |
vaAccountNumber | string | ~ | VA account number or identification account. Required when uuid is not passed. |
amount | number | ✓ | Amount to pay (VND). |
qrCode | string | ✓ | Dynamic QR Code string (Dynamic QR). |
bankBin | string | ~ | Bank BIN. See Supported banks. When uuid is not passed, you must pass bankBin or bankName. |
bankName | string | ~ | Bank name (per BankNameEnum): OCB, BIDV, MBB, ACB, VPB, PGB, VIB, STB, CTG, VCB, AGRIBANK, SHINHAN, COB, MSB, NEXTPAY, PAYOO, BAOKIM, TPB. When uuid is not passed, you must pass bankBin or bankName; if bankBin is passed, bankName is derived from bankBin. |
deviceType | string | ~ | Type of device to show the QR on: tingee-box-6xs or tingee-box-3ls. Required when uuid is not passed. |
firstText | string | ✕ | Text shown with the QR (line 1). |
secondText | string | ✕ | Text shown with the QR (line 2). |
thirdText | string | ✕ | Text shown with the QR (line 3). |
showTime | number | ✕ | How long the QR is shown on the screen (seconds). Default 90. Applies to TingeeBox 6XS (TingeeBox 3LS always shows it for 30 seconds). |
isStaticQr | boolean | ✕ | true: show it as a static QR (equivalent to the static QR API). Default false (dynamic QR). |
playSound | boolean | ✕ | true to play a beep when showing the QR. |
Code samples
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/device/show-dynamic-qr-code' \
--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 '{
"vaAccountNumber": "V1T123456789",
"amount": 150000,
"qrCode": "00020101021138580010A000000727...",
"bankBin": "970422",
"deviceType": "tingee-box-3ls"
}'
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 deviceShowDynamicQrCode() {
const body = {
vaAccountNumber: "V1T123456789",
amount: 150000,
qrCode: "00020101021138580010A000000727...",
bankBin: "970422",
deviceType: "tingee-box-3ls",
};
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/device/show-dynamic-qr-code",
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);
}
deviceShowDynamicQrCode();
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
{
vaAccountNumber = "V1T123456789",
amount = 150000,
qrCode = "00020101021138580010A000000727...",
bankBin = "970422",
deviceType = "tingee-box-3ls"
};
// 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/device/show-dynamic-qr-code");
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 = "{\"vaAccountNumber\":\"V1T123456789\",\"amount\":150000,\"qrCode\":\"00020101021138580010A000000727...\",\"bankBin\":\"970422\",\"deviceType\":\"tingee-box-3ls\"}";
// 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/device/show-dynamic-qr-code"))
.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 = [
"vaAccountNumber" => "V1T123456789",
"amount" => 150000,
"qrCode" => "00020101021138580010A000000727...",
"bankBin" => "970422",
"deviceType" => "tingee-box-3ls",
];
// 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/device/show-dynamic-qr-code",
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": null
}
| Field | Type | Description |
|---|---|---|
code | string | Result code (00 = success). |
message | string | Response message. |
POST
URLhttps://open-api.tingee.vn/v1/device/show-static-qr-code
Send a static QR code to the TINGEEBOX device to show to customers.
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 |
|---|---|---|---|
merchantId | number | ~ | Merchant ID (Required if you connect with a Master Merchant account). |
uuid | string | ~ | Device code. Pass uuid, or the trio bankBin (or bankName) + vaAccountNumber + deviceType so the system finds the devices attached to the account (via the account or the shop that contains it). When uuid is passed, vaAccountNumber, bankBin, bankName and deviceType are ignored. Currently only TingeeBox 6XS and TingeeBox 3LS devices can show QR codes. |
vaAccountNumber | string | ~ | VA account number or identification account. Required when uuid is not passed. |
amount | number | ✓ | Amount to pay (VND). |
qrCode | string | ✓ | Static QR Code string (VietQR). |
bankBin | string | ~ | Bank BIN. See Supported banks. When uuid is not passed, you must pass bankBin or bankName. |
bankName | string | ~ | Bank name (per BankNameEnum): OCB, BIDV, MBB, ACB, VPB, PGB, VIB, STB, CTG, VCB, AGRIBANK, SHINHAN, COB, MSB, NEXTPAY, PAYOO, BAOKIM, TPB. When uuid is not passed, you must pass bankBin or bankName; if bankBin is passed, bankName is derived from bankBin. |
deviceType | string | ~ | Type of device to show the QR on: tingee-box-6xs or tingee-box-3ls. Required when uuid is not passed. |
firstText | string | ✕ | Text shown with the QR (line 1). |
secondText | string | ✕ | Text shown with the QR (line 2). |
thirdText | string | ✕ | Text shown with the QR (line 3). |
showTime | number | ✕ | Has no effect for static QR (TingeeBox 6XS saves the static QR as its idle screen). |
playSound | boolean | ✕ | Has no effect for static QR. |
Code samples
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/device/show-static-qr-code' \
--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 '{
"vaAccountNumber": "V1T123456789",
"amount": 150000,
"qrCode": "00020101021138580010A00000072701240006970422011001234567890208QRIBFTTA5204541153037045802VN62180814Thanh toan don6304CA68",
"bankBin": "970422",
"deviceType": "tingee-box-3ls"
}'
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 deviceShowStaticQrCode() {
const body = {
vaAccountNumber: "V1T123456789",
amount: 150000,
qrCode: "00020101021138580010A00000072701240006970422011001234567890208QRIBFTTA5204541153037045802VN62180814Thanh toan don6304CA68",
bankBin: "970422",
deviceType: "tingee-box-3ls",
};
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/device/show-static-qr-code",
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);
}
deviceShowStaticQrCode();
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
{
vaAccountNumber = "V1T123456789",
amount = 150000,
qrCode = "00020101021138580010A00000072701240006970422011001234567890208QRIBFTTA5204541153037045802VN62180814Thanh toan don6304CA68",
bankBin = "970422",
deviceType = "tingee-box-3ls"
};
// 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/device/show-static-qr-code");
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 = "{\"vaAccountNumber\":\"V1T123456789\",\"amount\":150000,\"qrCode\":\"00020101021138580010A00000072701240006970422011001234567890208QRIBFTTA5204541153037045802VN62180814Thanh toan don6304CA68\",\"bankBin\":\"970422\",\"deviceType\":\"tingee-box-3ls\"}";
// 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/device/show-static-qr-code"))
.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 = [
"vaAccountNumber" => "V1T123456789",
"amount" => 150000,
"qrCode" => "00020101021138580010A00000072701240006970422011001234567890208QRIBFTTA5204541153037045802VN62180814Thanh toan don6304CA68",
"bankBin" => "970422",
"deviceType" => "tingee-box-3ls",
];
// 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/device/show-static-qr-code",
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": null
}
| Field | Type | Description |
|---|---|---|
code | string | Result code (00 = success). |
message | string | Response message. |
Common error codes
| Code | Description | How to handle |
|---|---|---|
1028 | Device not found | Check that the device uuid is linked to the Merchant. |
1053 | Device type not found | When uuid is not passed, you must pass a valid deviceType. |
1047 | Virtual account number not found | Check that vaAccountNumber and bankBin belong to the Merchant. |
1031 | Shop not found | The account has not been assigned to a shop with a device; check the device-to-shop link. |
1095, 1096 | Master Merchant merchantId error | Pass the merchantId of a sub-Merchant that belongs to the calling Master Merchant. |
90, 91, 92, 97 | Request authentication error (timestamp, client-id, signature) | See System error codes. |
Others | Other errors | See Error codes. |