API công khai TinoPay
API công khai của TinoPay chạy tại https://pay.tino.vn: truy vấn lịch sử giao dịch, lấy danh sách ngân hàng và sinh ảnh mã VietQR. API này khác API merchant (https://api.tino.vn/service/<id>/tinopay/…, token đăng nhập Tino) dùng để quản lý merchant, tài khoản ngân hàng, webhook.
Cập nhật: 2026-10-25. Nguồn: tài liệu TinoPay.
Hai cách tích hợp
| Hướng | Mô tả | Dùng khi |
|---|---|---|
| API | bạn gọi tới TinoPay để truy vấn dữ liệu (lịch sử giao dịch, danh sách ngân hàng) và sinh mã QR | kiểm tra, đối soát, hiện QR thanh toán |
| Webhook | TinoPay gửi dữ liệu giao dịch tới URL của bạn ngay khi phát sinh | xác nhận thanh toán tức thời, không cần hỏi lặp |
Nên dùng webhook để nhận giao dịch tức thời và dùng lịch sử giao dịch để đối soát hoặc dự phòng.
Thông tin cơ bản
| Mục | Giá trị |
|---|---|
| Địa chỉ gốc | https://pay.tino.vn |
| Tiền tố | endpoint API nằm dưới /api, ví dụ https://pay.tino.vn/api/transactions; riêng ảnh QR ở https://pay.tino.vn/img-qr |
| Định dạng | JSON, UTF-8 |
| Tiền tệ | VND, số nguyên, không có phần thập phân |
| Xác thực | Authorization: Bearer <api_token>, trừ danh sách ngân hàng và ảnh QR |
curl -G "https://pay.tino.vn/api/transactions" \
-H "Authorization: Bearer $TINOPAY_API_TOKEN" \
-H "Accept: application/json"Xác thực
Mọi request cần xác thực gửi API token ở header Authorization theo chuẩn Bearer:
Authorization: Bearer <api_token>Tạo API token
- Trên web TinoPay: menu Tích hợp → API Access (
/api-access), bấm Tạo API Token, đặt tên gợi nhớ (ví dụserver-production) rồi sao chép token ngay. - Bằng API merchant: Tạo API token, xem mục API token của trang Bắt đầu.
Token gốc chỉ hiện một lần khi tạo. Làm mất thì thu hồi token cũ và tạo token mới. Tạo được nhiều token và thu hồi bất kỳ token nào ở trang API Access.
Phạm vi truy cập
- Mỗi token gắn với một tài khoản chủ sở hữu và chỉ đọc được dữ liệu (giao dịch, tài khoản ngân hàng) của chủ token đó.
- Tham số trỏ tới tài nguyên không thuộc về bạn (ví dụ
bank_account_idcủa người khác) thì API không trả dữ liệu.
Ví dụ gọi
JavaScript:
const res = await fetch("https://pay.tino.vn/api/transactions", {
headers: { Authorization: `Bearer ${process.env.TINOPAY_API_TOKEN}`, Accept: "application/json" },
});
const data = await res.json();PHP (Laravel):
$response = Http::withToken(env('TINOPAY_API_TOKEN'))
->acceptJson()
->get('https://pay.tino.vn/api/transactions');
$data = $response->json();Lỗi xác thực
| Tình huống | HTTP | Body |
|---|---|---|
thiếu hoặc sai định dạng header Authorization | 401 | {"message": "Thiếu API Token. Vui lòng gửi header Authorization: Bearer {token}."} |
| token không tồn tại hoặc đã bị thu hồi | 401 | {"message": "API Token không hợp lệ."} |
Bảo mật
- TinoPay lưu token dưới dạng băm SHA-256, không lưu token gốc: token gốc chỉ xem được một lần khi tạo.
- Mỗi request hợp lệ cập nhật thời điểm dùng gần nhất (
last_used_at) của token, giúp theo dõi token nào đang hoạt động. - Không đưa token vào mã phía client (trình duyệt, app di động) hay commit lên Git: chỉ dùng ở máy chủ.
- Token bị lộ thì thu hồi ngay ở trang API Access; token đã thu hồi trả 401 từ request kế tiếp.
Lịch sử giao dịch
GET https://pay.tino.vn/api/transactions- Xác thực: bắt buộc.
- Trả giao dịch của mọi tài khoản ngân hàng thuộc chủ token.
- Mặc định lấy giao dịch trong ngày hiện tại; khoảng khác thì truyền
transaction_date_from,transaction_date_to. - Sắp xếp theo
transaction_dategiảm dần (mới nhất trước), có phân trang.
Tham số truy vấn, đều tuỳ chọn:
| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
q | string | — | tìm (LIKE) theo reference_number, transaction_content, transaction_id |
bank_account_id | string (UUID) | — | lọc theo một tài khoản ngân hàng; UUID phải thuộc chủ token |
type | string | — | in tiền vào, out tiền ra |
transaction_date_from | date (Y-m-d) | hôm nay | ngày bắt đầu (tính cả ngày này) |
transaction_date_to | date (Y-m-d) | hôm nay | ngày kết thúc (tính cả ngày này); tối đa 90 ngày kể từ from |
per_page | int (1–100) | 20 | số bản ghi mỗi trang |
page | int | 1 | trang hiện tại |
Khoảng thời gian:
- Không truyền cả
fromlẫnto: lấy trong ngày hôm nay. - Chỉ truyền một trong hai: lấy trọn đúng ngày đó.
fromphải nhỏ hơn hoặc bằngto, cách nhau tối đa 90 ngày.
curl -G "https://pay.tino.vn/api/transactions" \
-H "Authorization: Bearer $TINOPAY_API_TOKEN" \
-H "Accept: application/json" \
--data-urlencode "q=DH12345" \
--data-urlencode "type=in" \
--data-urlencode "transaction_date_from=2026-10-01" \
--data-urlencode "transaction_date_to=2026-10-20" \
--data-urlencode "per_page=20"const params = new URLSearchParams({ q: "DH12345", type: "in", transaction_date_from: "2026-10-01", transaction_date_to: "2026-10-20", per_page: "20" });
const res = await fetch(`https://pay.tino.vn/api/transactions?${params}`, {
headers: { Authorization: `Bearer ${process.env.TINOPAY_API_TOKEN}`, Accept: "application/json" },
});
const json = await res.json();Response 200:
{
"data": [
{
"id": 1032,
"reference_number": "0551dTCO-82LiomOss",
"transaction_content": "DH12345 chuyen tien mua hang",
"transaction_id": "20261020083338000006",
"bank_account_id": "9c1e6f2a-5b7d-4e1a-9f3c-2d8b6a4e0c11",
"virtual_number": "9624QA01",
"amount": 150000,
"type": 1,
"type_label": "in",
"status": 0,
"transaction_date": "2026-10-20 08:33:38",
"created_at": "2026-10-20 08:33:40"
}
],
"links": {
"first": "https://pay.tino.vn/api/transactions?page=1",
"last": "https://pay.tino.vn/api/transactions?page=3",
"prev": null,
"next": "https://pay.tino.vn/api/transactions?page=2"
},
"meta": { "current_page": 1, "from": 1, "last_page": 3, "per_page": 20, "to": 20, "total": 57 }
}Trường trong data[] | Kiểu | Mô tả |
|---|---|---|
id | int | ID giao dịch |
reference_number | string | null | mã tham chiếu của ngân hàng (core reference) |
transaction_content | string | nội dung, diễn giải giao dịch |
transaction_id | string | mã giao dịch |
bank_account_id | string (UUID) | tài khoản ngân hàng phát sinh giao dịch |
virtual_number | string | null | số tài khoản ảo, nếu có |
amount | int | số tiền (VND) |
type | int | 1 tiền vào, 2 tiền ra |
type_label | string | in tiền vào, out tiền ra |
status | int | trạng thái giao dịch |
transaction_date | string (Y-m-d H:i:s) | thời điểm giao dịch thực tế |
created_at | string (Y-m-d H:i:s) | thời điểm TinoPay ghi nhận |
links và meta là cấu trúc phân trang của Laravel API Resource: duyệt trang theo meta.last_page hoặc links.next.
| Lỗi | HTTP | Body |
|---|---|---|
from lớn hơn to | 422 | {"message": "transaction_date_from phải nhỏ hơn hoặc bằng transaction_date_to."} |
| khoảng quá 90 ngày | 422 | {"message": "Khoảng thời gian tối đa là 90 ngày."} |
| sai kiểu dữ liệu tham số | 422 | lỗi validate của Laravel: {"message": …, "errors": {…}} |
Danh sách ngân hàng
GET https://pay.tino.vn/api/banksNgân hàng TinoPay hỗ trợ, kèm mã ngân hàng (code) và mã BIN: dùng cho ô chọn ngân hàng hoặc lấy code để tạo mã VietQR. Không cần xác thực. Trả một mảng JSON, không bọc trong data.
curl "https://pay.tino.vn/api/banks" -H "Accept: application/json"[
{ "id": 1, "code": "BIDV", "bin": "970418", "name": "Ngân hàng TMCP Đầu tư và Phát triển Việt Nam", "created_at": "2025-01-01 00:00:00", "updated_at": "2025-01-01 00:00:00" },
{ "id": 2, "code": "MB", "bin": "970422", "name": "Ngân hàng TMCP Quân đội", "created_at": "2025-01-01 00:00:00", "updated_at": "2025-01-01 00:00:00" }
]| Trường | Kiểu | Mô tả |
|---|---|---|
id | int | ID ngân hàng trong TinoPay |
code | string | mã viết tắt (ví dụ BIDV, MB), dùng cho tham số bank_code khi tạo mã QR |
bin | string | mã định danh ngân hàng (BIN) theo chuẩn Napas, VietQR |
name | string | tên đầy đủ của ngân hàng |
Danh sách theo đúng dữ liệu ngân hàng đang cấu hình trong TinoPay: dùng nguyên giá trị code từ đây khi gọi API khác.
Tạo mã VietQR
GET https://pay.tino.vn/img-qrSinh mã VietQR động để khách quét và chuyển khoản. Endpoint trả thẳng ảnh PNG nên nhúng được vào thẻ <img>, không cần tự vẽ QR.
- Không cần xác thực. Không có tiền tố
/api. - Trả ảnh
image/png, có headerAccess-Control-Allow-Origin: *nên dùng được từ trình duyệt. - Mã theo chuẩn VietQR, Napas 247 (dịch vụ chuyển nhanh QRIBFTTA).
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
bank_code | có | mã ngân hàng thụ hưởng (ví dụ BIDV, MB), lấy từ danh sách ngân hàng |
account_no | có | số tài khoản thụ hưởng |
account_name | không | tên chủ tài khoản, hiện trên khung ảnh |
amount | không | số tiền (VND); chỉ áp dụng khi trong khoảng 1.000 – 9.999.999.999.999 |
memo | không | nội dung chuyển khoản, tối đa 25 ký tự (dài hơn thì bị bỏ qua) |
template | không | default ảnh có khung (mặc định), only-qr chỉ mã QR |
is_mask | không | 1: che bớt số tài khoản trên ảnh có khung |
<img src="https://pay.tino.vn/img-qr?bank_code=BIDV&account_no=96240000001&amount=150000&memo=DH12345" alt="Quét QR để thanh toán" width="320">Đủ tham số:
https://pay.tino.vn/img-qr?bank_code=BIDV&account_no=96240000001&account_name=CONG%20TY%20ABC&amount=150000&memo=DH12345&template=default&is_mask=1Chỉ mã QR, không khung:
https://pay.tino.vn/img-qr?bank_code=BIDV&account_no=96240000001&amount=150000&memo=DH12345&template=only-qrThiếu hoặc sai tham số bắt buộc thì endpoint trả văn bản, không phải ảnh:
| Tình huống | Trả về |
|---|---|
bank_code không hợp lệ hoặc không có | Vui lòng nhập đúng mã ngân hàng |
thiếu account_no | Vui lòng nhập số tài khoản |
Trong luồng thanh toán, đặt memo là mã đơn hàng duy nhất (ví dụ DH12345). Khi khách chuyển khoản, webhook nhận giao dịch kèm nội dung này (và code nếu khớp mã thanh toán), nhờ đó khớp đúng đơn hàng và xác nhận thanh toán tự động.
Hỗ trợ
Vướng mắc khi tích hợp: tạo ticket hỗ trợ ngay trong trang quản trị TinoPay.