# Bắt đầu với TinoPay

TinoPay là dịch vụ nhận thanh toán chuyển khoản của Tino: khách của bạn chuyển khoản vào tài khoản ngân hàng đã liên kết, hoặc vào một tài khoản ảo (VA) riêng; TinoPay ghi nhận giao dịch, gửi webhook tới hệ thống của bạn và thông báo vào Telegram, Zalo, Lark. Tài khoản ngân hàng, tài khoản ảo, giao dịch, webhook và thông báo nằm ở hệ thống TinoPay (`https://pay.tino.vn`); API merchant của dịch vụ trên `api.tino.vn` chuyển tiếp tới đó. TinoPay còn có [API công khai](/docs/tinopay-api) gọi bằng API token và [tích hợp không cần code](/docs/tinopay-integrations) (Google Sheets, WordPress / WooCommerce, HostBill, Sapo).

Cập nhật: 2026-10-25. Nguồn: module TinoPay của Tino và tài liệu TinoPay API v1.

## Thiết lập

1. Đặt mua dịch vụ TinoPay ở tino.vn: mỗi dịch vụ là một merchant.
2. Liên kết tài khoản ngân hàng. Với BIDV doanh nghiệp, gửi [yêu cầu liên kết](/docs/api/tinopay-post-bank-links-bidv-business); nhân viên mở dịch vụ với BIDV, xong thì tài khoản hiện ở [danh sách tài khoản ngân hàng](/docs/api/tinopay-get-bank-accounts).
3. Tạo [tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts) khi cần tách tiền theo đơn hàng, cửa hàng hay khách: số VA là mã đầu VA của tài khoản ngân hàng (`first_va_number`) cộng phần đuôi bạn chọn.
4. Khai [mã thanh toán](/docs/api/tinopay-patch-merchant) (`pay_codes`) nếu muốn TinoPay trích mã đơn hàng từ nội dung chuyển khoản.
5. Tạo webhook để nhận từng giao dịch: xem [Nhận webhook TinoPay](/docs/tinopay-webhook).
6. Muốn báo từng giao dịch vào nhóm chat: xem [Thông báo Telegram, Zalo, Lark](/docs/tinopay-notifications). Muốn tự đọc giao dịch bằng [API công khai](/docs/tinopay-api) của TinoPay: tạo [API token](#api-token).

## Gọi API merchant

| Mục | Giá trị |
| --- | --- |
| Địa chỉ | `https://api.tino.vn/service/<id dịch vụ>/tinopay/…` |
| Xác thực | `Authorization: Bearer <token>`: token đăng nhập của chủ dịch vụ TinoPay; qua `/v1`: token ứng dụng OAuth hoặc token API cá nhân có quyền `tinopay:*` |
| Body | JSON, `Content-Type: application/json` |
| Từng route | mục TinoPay ở [API Reference](/docs/reference#tinopay) |

- `PATCH` bắt buộc body JSON: API không đọc body dạng form (`application/x-www-form-urlencoded`) của `PATCH`. Với `PATCH`, chỉ gửi trường cần đổi.
- Chỉ các tham số ghi ở từng route được chuyển tiếp; tham số khác bị bỏ qua.
- ID trong đường dẫn sau ID dịch vụ (tài khoản ngân hàng, tài khoản ảo, webhook, log, giao dịch, ứng dụng thông báo, API token) chỉ gồm chữ, số, `-`, tối đa 64 ký tự; sai dạng trả 404 `RESOURCE_NOT_FOUND`.
- Timeout: Tino chờ TinoPay tối đa 30 giây mỗi lần và tự thử lại tới 3 lần (cách 1 giây, 2 giây) khi lỗi mạng hoặc lỗi 5xx ở các lệnh thử lại an toàn, nên khi TinoPay chậm một request có thể mất khoảng 95 giây. Đặt timeout ít nhất 100 giây (hoặc báo đang xử lý và cho huỷ). Proxy phía trước có thể cắt sớm hơn và trả 504 với body HTML, không phải JSON: xử lý như lỗi kết nối 502. Tìm nơi nhận của bot Zalo luôn mất khoảng 20 giây.

Từ 27/10/2026 các route TinoPay cũng gọi được qua gateway `/v1`: `https://api.tino.vn/v1/service/<id dịch vụ>/tinopay/…` với token ứng dụng OAuth (`tinoat_`, quyền `tinopay:read`, `tinopay:write`) hoặc [token API cá nhân](/docs/personal-tokens) (`tinopat_`), cùng body và câu trả lời. Tạo, xoá API token TinoPay và liên kết tài khoản ngân hàng nhận tiền cần `tinopay:owner`: chỉ token cá nhân có giới hạn IP, ứng dụng OAuth không bao giờ có. Plugin hay phần mềm của bên thứ ba (ví dụ plugin WooCommerce) nên xin quyền qua [Đăng nhập bằng Tino](/docs/oauth), không hỏi token đăng nhập của khách.

Token đăng nhập (token khách dùng ở khu vực khách hàng tino.vn) vẫn gọi thẳng `https://api.tino.vn/service/<id dịch vụ>/tinopay/…`; [SDK](/docs/sdk) lấy được bằng đăng nhập mã OTP:

```python
from tino_userapi import TinoClient

client = TinoClient()
client.request_login_otp("you@example.com")
client.verify_login_otp("you@example.com", input("Mã OTP: "))
print(client.request("GET", "/service/100001/tinopay/transactions", query={"type": "in"}))
```

`100001` là ID dịch vụ TinoPay: cách tìm ở mục dưới.

## Tìm dịch vụ TinoPay

Mỗi tài khoản Tino có tối đa một dịch vụ TinoPay, ứng với một merchant.

1. Nhận diện bằng loại sản phẩm, không theo nhóm hay tên (TinoPay nằm trong nhóm "Dịch vụ khác" dùng chung với dịch vụ khác):

| Route (cùng token đăng nhập) | Trường | Giá trị của TinoPay |
| --- | --- | --- |
| `GET https://api.tino.vn/service` ([Danh sách dịch vụ](/docs/api/get-service)) | `product_type` | `"tinopay"` |
| `GET https://api.tino.vn/service/<id>` | `service.ptype` | `"tinopaypanel"` |

2. Khi mở phần quản lý, gọi [Thông tin merchant](/docs/api/tinopay-get-merchant) (`GET /service/<id>/tinopay`):

| Kết quả | Nghĩa |
| --- | --- |
| 200 | dịch vụ TinoPay đang chạy: quản lý merchant được |
| 403 `service_not_active` | dịch vụ TinoPay đang chờ kích hoạt, đã huỷ hoặc bị khoá (Pending, Terminated, Cancelled, Fraud): chỉ hiện trạng thái dịch vụ |
| 404 `invalid method` | dịch vụ không phải TinoPay hoặc không tồn tại: dịch vụ không gắn TinoPay không có route TinoPay |
| 404 `service_not_found` | dịch vụ TinoPay của tài khoản khác |
| 404 `MERCHANT_NOT_FOUND` | dịch vụ đã kích hoạt nhưng merchant đang khởi tạo; quá lâu thì liên hệ hỗ trợ Tino |

## Trạng thái merchant

| Dịch vụ | `data.status` | Đọc (`GET`) | Ghi (tạo, sửa, xoá, gửi lại) |
| --- | --- | --- | --- |
| Active | `active` | được | được |
| Suspended | `suspended` | được | 403 `MERCHANT_SUSPENDED` |
| — | `terminated` | 403 `MERCHANT_TERMINATED` | 403 `MERCHANT_TERMINATED` |

Khi `data.status` là `suspended` (hoặc `data.suspended_at` khác `null`): báo khách dịch vụ đang tạm ngưng (thanh toán hoá đơn để mở lại) và khoá mọi thao tác ghi. Trong lúc tạm ngưng, giao dịch từ ngân hàng vẫn được ghi nhận nhưng không gửi webhook; mở lại thì tài khoản ngân hàng về trạng thái cũ, đối chiếu giao dịch bỏ lỡ bằng [lịch sử giao dịch](/docs/api/tinopay-get-transactions) với `webhook_status=none`.

## Câu trả lời

Thành công: `{"data": …}`; danh sách phân trang có thêm `meta`. HTTP 200, 201 khi tạo mới, 202 khi đã xếp hàng gửi lại webhook.

```json
{ "data": [], "meta": { "page": 1, "per_page": 20, "total": 135, "last_page": 7 } }
```

Danh sách phân trang nhận `page` và `per_page` (tối đa 100).

## API token

API token dùng để gọi [API công khai](/docs/tinopay-api) của TinoPay, ví dụ `GET https://pay.tino.vn/api/transactions` (header `Authorization: Bearer <token>`), cùng dữ liệu với trang API Access trên web TinoPay.

- [Tạo API token](/docs/api/tinopay-post-api-tokens) (`{name}`) trả `token` 64 ký tự **chỉ một lần**, trong câu trả lời 201: đưa cho khách sao chép, không lưu, không ghi log. TinoPay chỉ lưu bản băm nên [danh sách](/docs/api/tinopay-get-api-tokens) không có token.
- Không tự thử lại khi lỗi mạng (mỗi lần gọi tạo một token): đọc lại danh sách, thấy token thừa thì [thu hồi](/docs/api/tinopay-delete-api-tokens-token). Thu hồi có hiệu lực ngay.

## Lỗi

```json
{ "error": ["VA_NUMBER_EXISTS"], "message": "Số VA đã tồn tại.", "details": { "account_number": "9624QA01" }, "request_id": "…" }
```

Rẽ nhánh theo `error[0]`, không theo `message` (câu tiếng Việt, có thể đổi); `message` chỉ dùng làm câu dự phòng. Với `VALIDATION_FAILED`, `details` là lỗi theo từng trường. Lỗi Tino trả trước khi chuyển tiếp (`service_not_found`, `service_not_active`, `invalid method`, `RESOURCE_NOT_FOUND` vì ID sai dạng hoặc webhook, ứng dụng thông báo không thuộc merchant) chỉ có `error`. Khi báo lỗi cho Tino, gửi kèm `request_id`.

| HTTP | Mã | Nghĩa, cách xử lý |
| --- | --- | --- |
| 400 | `INVALID_REQUEST` | sai method hoặc body: lỗi lập trình phía ứng dụng |
| 401 | `unauthorized`, `invalid_token`, `token_expired` | token đăng nhập sai hoặc hết hạn: làm mới token |
| 403 | `service_not_active` | dịch vụ không ở trạng thái Active hoặc Suspended: chỉ hiện trạng thái dịch vụ |
| 403 | `MERCHANT_SUSPENDED` | merchant đang tạm ngưng: chặn thao tác ghi, `GET` vẫn dùng được |
| 403 | `MERCHANT_TERMINATED` | merchant đã huỷ: chặn mọi route |
| 404 | `service_not_found`, `invalid method` | không phải dịch vụ TinoPay của tài khoản đang đăng nhập: về danh sách dịch vụ |
| 404 | `MERCHANT_NOT_FOUND` | merchant đang khởi tạo |
| 404 | `BANK_ACCOUNT_NOT_FOUND` | tài khoản ngân hàng không có hoặc không thuộc merchant |
| 404 | `RESOURCE_NOT_FOUND` | tài khoản ảo, webhook, log, giao dịch, ứng dụng thông báo, API token không có, đã xoá hoặc không thuộc merchant; ID sai dạng. Tải lại danh sách |
| 409 | `VA_NUMBER_EXISTS` | số tài khoản ảo đã có |
| 409 | `EMAIL_TAKEN` | email đang thuộc một khách Tino khác |
| 409 | `IDEMPOTENCY_CONFLICT` | hiếm: thao tác trước đang xử lý, thử lại sau ít giây |
| 422 | `VALIDATION_FAILED` | dữ liệu sai; `details` liệt kê lỗi theo trường |
| 429 | `RATE_LIMITED` | vượt 300 request mỗi phút cho mỗi merchant: thử lại sau 1 phút |
| 500 | `INTERNAL_ERROR` | lỗi phía TinoPay: thử lại sau, báo Tino kèm `request_id` |
| 502 | `NETWORK_ERROR`, `NOT_CONFIGURED`, `UNEXPECTED_RESPONSE`, `MISSING_API_KEY`, `INVALID_KEY`, `IP_NOT_ALLOWED` | kết nối giữa Tino và TinoPay gián đoạn: lỗi phía Tino, không phải lỗi token hay phiên đăng nhập. Đừng xoá token hay đăng xuất khách; thử lại sau, kéo dài thì báo Tino kèm `request_id` |
| 504 | (body HTML) | proxy cắt request chậm trước khi có câu trả lời: xử lý như 502, thử lại sau |

Mã không có trong bảng: hiện `message` (nếu có) hoặc câu chung, kèm `request_id`.

## Lưu ý

- `POST` không tự chống lặp: gọi lại một `POST` (ví dụ tạo tài khoản ảo) là một yêu cầu mới. Đọc lại danh sách trước khi thử lại.
- Tên, email, số điện thoại của merchant không tự đồng bộ với hồ sơ Tino của khách: chỉ đổi qua [Sửa thông tin merchant](/docs/api/tinopay-patch-merchant).
- `token` của webhook là bí mật của khách: khi hiện trên giao diện, che đi và chỉ hiện khi khách bấm xem.
- Tìm nơi nhận, gửi tin thử của thông báo và tạo API token không tự thử lại khi lỗi mạng: để người dùng bấm lại.
