Tạo đơn hàng POS
API này dùng để tạo đơn hàng thanh toán và đẩy xuống máy POS đã liên kết. Khách hàng thanh toán đơn hàng trực tiếp trên máy POS bằng thẻ hoặc mã QR.
POST
URLhttps://open-api.tingee.vn/v1/create-pos-bill
Tạo đơn hàng thanh toán trên máy POS Payoo. Kết quả trả về billId dùng để tra cứu, hủy đơn và đối soát Webhook.
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 sở hữu máy POS. Bắt buộc nếu kết nối bằng tài khoản Master Merchant. |
bankBin | string | ✓ | Truyền cố định PAYOO. |
vaAccountNumber | string | ✓ | Mã thiết bị POS Payoo đã liên kết (tối đa 50 ký tự). |
amount | number | ✓ | Số tiền cần thanh toán (VND, số nguyên dương). |
paymentMethod | string | ✕ | Phương thức thanh toán hiển thị trên máy POS: - card: Thanh toán thẻ - qr: Thanh toán bằng mã QR Bỏ trống (hoặc giá trị khác) để máy POS cho phép khách hàng tự chọn. |
purpose | string | ✕ | Nội dung thanh toán, hiển thị trên máy POS. |
expireInMinute | number | ✕ | Thời gian hiệu lực của đơn hàng (phút), từ 1 đến 43200. Mặc định 43200 (30 ngày). |
extraInfo | string | ✕ | Thông tin bổ sung của đối tác (tối đa 200 ký tự), được gửi kèm trong Webhook thanh toán. |
Ví dụ mã nguồn
- cURL
- NestJS
- C#
- Java
- PHP
curl --location --request POST 'https://open-api.tingee.vn/v1/create-pos-bill' \
--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": "PAYOO",
"vaAccountNumber": "POS00012345",
"amount": 150000,
"paymentMethod": "card",
"purpose": "Thanh toan don hang DH001",
"expireInMinute": 30,
"extraInfo": "DH001"
}'
import axios from "axios";
import { createHmac } from "crypto";
const CLIENT_ID = "YOUR_CLIENT_ID";
const SECRET_KEY = "YOUR_SECRET_KEY";
// Timestamp theo múi giờ UTC+7, định dạng yyyyMMddHHmmssSSS
function getTimestamp() {
return new Date(Date.now() + 7 * 60 * 60 * 1000)
.toISOString()
.replace(/[-:TZ.]/g, "")
.slice(0, 17);
}
async function createPosBill() {
const body = {
bankBin: "PAYOO",
vaAccountNumber: "POS00012345",
amount: 150000,
paymentMethod: "card",
purpose: "Thanh toan don hang DH001",
expireInMinute: 30,
extraInfo: "DH001",
};
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-pos-bill",
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);
}
createPosBill();
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 = "PAYOO",
vaAccountNumber = "POS00012345",
amount = 150000,
paymentMethod = "card",
purpose = "Thanh toan don hang DH001",
expireInMinute = 30,
extraInfo = "DH001"
};
// Không escape tiếng Việt / ký tự đặc biệt để khớp với JSON.stringify phía TINGEE
var jsonOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
var bodyJson = JsonSerializer.Serialize(body, jsonOptions);
// Timestamp theo múi giờ UTC+7, định dạng 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-pos-bill");
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 {
// JSON minified, giống kết quả JSON.stringify()
String bodyJson = "{\"bankBin\":\"PAYOO\",\"vaAccountNumber\":\"POS00012345\",\"amount\":150000,\"paymentMethod\":\"card\",\"purpose\":\"Thanh toan don hang DH001\",\"expireInMinute\":30,\"extraInfo\":\"DH001\"}";
// Timestamp theo múi giờ UTC+7, định dạng 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-pos-bill"))
.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" => "PAYOO",
"vaAccountNumber" => "POS00012345",
"amount" => 150000,
"paymentMethod" => "card",
"purpose" => "Thanh toan don hang DH001",
"expireInMinute" => 30,
"extraInfo" => "DH001",
];
// Không escape "/" và tiếng Việt để khớp với JSON.stringify phía TINGEE
$bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
// Timestamp theo múi giờ UTC+7, định dạng 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-pos-bill",
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);
Response mẫu
{
"code": "00",
"message": "Success",
"data": {
"billId": "9f1c2b7e4a5d4c3b8e2f1a0b9c8d7e6f",
"amount": 150000,
"expireInMinute": 30,
"purpose": "Thanh toan don hang DH001"
}
}
| 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.billId | string | Mã đơn hàng (32 ký tự). Dùng để tra cứu, hủy đơn và đối soát Webhook thanh toán. |
data.amount | number | Số tiền của đơn hàng. |
data.expireInMinute | number | Thời gian hiệu lực của đơn hàng (phút); 43200 nếu không truyền khi tạo. |
data.purpose | string | Nội dung thanh toán (không trả về nếu không truyền khi tạo). |
Mã lỗi thường gặp
| Code | Mô tả | Hướng xử lý |
|---|---|---|
1024 | Số tài khoản ảo không tồn tại | Máy POS chưa được liên kết với Merchant. Liên kết bằng Tạo/Liên kết số tài khoản với bankBin = "PAYOO". |
1096 | Merchant ID không được bỏ trống | Tài khoản Master Merchant cần truyền merchantId. |
1095 | Merchant không thuộc Master Merchant | Kiểm tra merchantId thuộc Master Merchant đang gọi API. |
400 | Lỗi từ Payoo hoặc dữ liệu không hợp lệ | message chứa mô tả lỗi chi tiết từ Payoo hoặc từ bước kiểm tra dữ liệu. |
90, 91, 92, 97 | Lỗi xác thực request (timestamp, client-id, chữ ký) | Xem Mã lỗi hệ thống. |
Others | Lỗi khác | Xem Danh sách mã lỗi. |