# Dùng tài liệu với AI Mọi trang trên developers.tino.vn có bản Markdown cùng nội dung với trang HTML. Coding agent và LLM đọc bản Markdown (ít token, không cần chạy JavaScript) thay vì HTML; trang HTML khai bản này bằng ``. Cập nhật: 2026-10-21. ## Đường dẫn cho máy đọc | Đường dẫn | Nội dung | | --- | --- | | `https://developers.tino.vn/llms.txt` | Mục lục theo chuẩn llmstxt.org: mọi trang, mỗi dòng một link Markdown kèm tóm tắt | | `https://developers.tino.vn/llms-full.txt` | Toàn bộ tài liệu trong một file Markdown (gói ngữ cảnh) | | Đường dẫn trang + `.md` | Bản Markdown của một trang, ví dụ `/docs/oauth.md`, `/docs/api/get-details.md` | | `https://developers.tino.vn/openapi.json` | OpenAPI 3.1 của gateway `/v1`: mọi route, quyền (scope), tham số, mẫu response khi có | Trên mỗi trang: nút **Sao chép Markdown** chép bản Markdown của trang, **Xem .md** mở bản đó. Trang route có thêm **Sao chép ngữ cảnh**: trang route cùng trang [Gọi API Tino](/docs/api) (xác thực, cách gửi tham số, mã lỗi) trong một lần chép. ## Cho coding agent Dán vào yêu cầu, hoặc vào file hướng dẫn của dự án (`AGENTS.md`, `CLAUDE.md`…): ```text Tài liệu API Tino: đọc https://developers.tino.vn/llms.txt, rồi bản .md của các trang cần dùng (thêm .md vào đường dẫn trang). Gọi API Tino qua https://api.tino.vn/v1/ với header Authorization: Bearer . Mỗi route cần một quyền (scope); route ngoài quyền của token trả 403 insufficient_scope. Không ghi token vào mã nguồn: đọc từ biến môi trường TINO_TOKEN. ``` Máy sinh client (OpenAPI Generator, openapi-typescript…) đọc `https://developers.tino.vn/openapi.json`. Mẫu response bị rút gọn (`… N more item(s)`) không gắn làm `example` trong OpenAPI; xem bản đầy đủ hơn trên trang route. ## Trợ lý AI làm việc với tài khoản Tino Đọc tài liệu khác với thao tác trên tài khoản. Để Claude, ChatGPT xem và quản lý dịch vụ, tên miền, DNS, hoá đơn của khách trong phạm vi quyền khách đồng ý, dùng máy chủ MCP `https://api.tino.vn/mcp`: xem [Kết nối Claude, ChatGPT với Tino (MCP)](/docs/mcp). --- # Gọi API Tino Ứng dụng và phần mềm của khách gọi API Tino thay khách qua gateway `https://api.tino.vn/v1/`: mỗi route chạy route UserAPI cùng tên bằng tài khoản của khách, trong phạm vi quyền của token. Body và câu trả lời giữ nguyên dạng của UserAPI (xem [Dữ liệu cá nhân](#du-lieu-ca-nhan)). Trợ lý AI gọi cùng các route này dưới dạng tool qua [máy chủ MCP](/docs/mcp). Cập nhật: 2026-10-21. Danh sách route, quyền, tên và tham số đúng như gateway đang chạy; mẫu response là câu trả lời thật, đã che dữ liệu cá nhân. ## Xác thực Mọi route cần header `Authorization: Bearer `, một trong hai loại token: | Token | Tiền tố | Có từ đâu | Gọi được | | --- | --- | --- | --- | | Token ứng dụng (access token) | `tinoat_` | [Đăng nhập bằng Tino](/docs/oauth): khách đồng ý cấp quyền cho ứng dụng | route thuộc các quyền khách đã đồng ý; không bao giờ có `domains:owner` | | Token API cá nhân | `tinopat_` | [khách tự tạo](/docs/personal-tokens) ở `https://auth.tino.vn/me/security`, mục Token API | route thuộc các quyền khách chọn, kể cả `domains:owner` (bắt buộc giới hạn IP); chỉ từ IP trong danh sách nếu có | ```bash curl https://api.tino.vn/v1/details -H "Authorization: Bearer $TINO_TOKEN" ``` Mỗi trang route ghi quyền (scope) cần có và loại token gọi được. Ngoại lệ: route công khai không cần token và gọi thẳng `https://api.tino.vn` (không có `/v1`), hiện có [Tra whois tên miền](/docs/api/get-whois-domain) (`GET /whois/`). ## Gửi tham số - Tham số đường dẫn: tài liệu viết `@id`, `@vmid`…; thay bằng giá trị thật, ví dụ `GET /v1/service/12345`. - `GET`, `DELETE`: tham số ở query string. - `POST`, `PUT`: body JSON với `Content-Type: application/json`. Gateway cũng đọc query string, và body form (`application/x-www-form-urlencoded`). - Phân trang (các route danh sách có): `page` bắt đầu từ 0, `perpage` số dòng mỗi trang; câu trả lời có `page.current`, `page.total`. - Lọc và sắp xếp: `filter[]=`, `orderby=|DESC` hoặc `|ASC`. ## Dữ liệu cá nhân Gateway `/v1` trả nguyên câu trả lời của route, gồm cả thông tin định danh của tài khoản, liên hệ và chủ thể tên miền (số giấy tờ, ngày sinh, số điện thoại, địa chỉ, mã số thuế): token gọi được là của chủ tài khoản hoặc được chủ tài khoản cho phép. Giữ token như mật khẩu; không ghi log, không lưu các trường này khi ứng dụng không cần. [Máy chủ MCP](/docs/mcp) thì lọc các trường định danh trước khi gửi kết quả cho trợ lý AI. ## Lỗi Gateway từ chối bằng body `{"error": [""]}`; lỗi 401 và `insufficient_scope` kèm header `WWW-Authenticate: Bearer error=""` (có `scope` và `resource_metadata` cho client MCP). | HTTP | `error` | Nguyên nhân | Xử lý | | --- | --- | --- | --- | | 401 | `invalid_token` | token sai, hết hạn hoặc đã bị thu hồi | ứng dụng làm mới token; token cá nhân thì tạo token mới | | 403 | `insufficient_scope` | token không có quyền của route, hoặc route không có trong gateway | xin thêm quyền (ứng dụng) hoặc tạo token có thêm quyền (token cá nhân) | | 403 | `ip_not_allowed` | token API cá nhân gọi từ IP ngoài danh sách giới hạn | gọi từ IP đã khai, hoặc tạo token với danh sách IP mới | | 403 | `ipnotallowed` | IP gọi API đang bị Tino chặn | liên hệ Tino | Lỗi nghiệp vụ của từng route (ví dụ dịch vụ không tồn tại) giữ nguyên câu trả lời của UserAPI, thường là HTTP 200 kèm `{"error": [""]}`; thao tác thành công thường kèm `{"info": [""]}`. ## Danh sách route Mỗi route một trang: tham số, ví dụ cURL, JavaScript, PHP, mẫu response; mục lục theo sản phẩm ở [API Reference](/docs/reference), bản máy đọc ở [/openapi.json](/openapi.json). Bản Markdown cho LLM: thêm `.md` vào đường dẫn trang (ví dụ `/docs/api/get-details.md`); toàn bộ ở [/llms-full.txt](/llms-full.txt). --- # Bắt đầu với TinoPage Builder TinoPage Builder dựng website cho cơ sở kinh doanh bằng AI: khách kể về cơ sở, AI chọn mẫu và viết nội dung, khách sửa tiếp trong trình sửa của TinoPage Builder. Website nhận liên hệ, đơn hàng và chạy trên tên miền riêng. API của dịch vụ cho ứng dụng của bạn xem hạn mức, tạo website bằng AI, đăng, tạm ngưng, xoá website, gắn tên miền riêng, xem liên hệ, đơn hàng và mở TinoPage Builder bằng vé đăng nhập một lần. Cập nhật: 2026-10-26. Nguồn: module TinoPage Builder của Tino và API của TinoPage Builder. ## Gọi API | Mục | Giá trị | | --- | --- | | Địa chỉ | `https://api.tino.vn/service//builder/…` | | Xác thực | `Authorization: Bearer `: token đăng nhập của chủ dịch vụ TinoPage Builder; qua `/v1`: token ứng dụng OAuth hoặc token API cá nhân có quyền `builder:*` | | Body | JSON, `Content-Type: application/json` | | Từng route | mục TinoPage Builder ở [API Reference](/docs/reference#tinopage-builder) | - Chỉ các tham số ghi ở từng route được chuyển tiếp. Tino kiểm dạng trước khi gọi TinoPage Builder: ID website không phải UUID, tên miền sai dạng, query hay body lạ trả 400 `INVALID_REQUEST`, `details.field` chỉ trường. - ID website trong đường dẫn là UUID; tên miền trong đường dẫn viết chữ thường. - Sửa nội dung website (trang, khối, ảnh, mặt hàng) và xử lý liên hệ, đơn hàng làm trong TinoPage Builder: mở bằng [vé đăng nhập](#ve-dang-nhap). Từ 27/10/2026 các route TinoPage Builder cũng gọi được qua gateway `/v1`: `https://api.tino.vn/v1/service//builder/…` với token ứng dụng OAuth (`tinoat_`, quyền `builder:read`, `builder:write`) hoặc [token API cá nhân](/docs/personal-tokens) (`tinopat_`), cùng body và câu trả lời. Riêng [vé đăng nhập](#ve-dang-nhap) (`POST …/builder/login`) không mở qua `/v1`: chỉ token đăng nhập lấy được. Token đăng nhập là token khách dùng ở khu vực khách hàng tino.vn; [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/100003/builder/overview")) ``` `100003` là ID dịch vụ TinoPage Builder: cách tìm ở mục dưới. ## Tìm dịch vụ TinoPage Builder Mỗi khách Tino có một tài khoản TinoPage Builder, gắn với dịch vụ TinoPage Builder đã mua. 1. Lấy ứng viên ở [Danh sách dịch vụ](/docs/api/get-service) (`product_type`) hoặc [Chi tiết dịch vụ](/docs/api/get-service-id) (`ptype`): giá trị `tinobuilderpanel`. Dịch vụ không có giá trị này thì xem `acc_module`: `TinoPage Builder`. So không phân biệt hoa thường, bỏ khoảng trắng, `_`, `-`. 2. Gọi [Tổng quan tài khoản](/docs/api/builder-get-overview) (`GET /service//builder/overview`): | Kết quả | Nghĩa | | --- | --- | | 200 | dịch vụ TinoPage Builder của khách: gọi các route khác với ID này | | 404 `SERVICE_NOT_LINKED` | tài khoản TinoPage Builder đã gắn với dịch vụ khác của khách: thử dịch vụ kế tiếp | | 404 `SERVICE_NOT_FOUND`, `invalid method` | không phải dịch vụ TinoPage Builder của tài khoản đang đăng nhập | | 404 `ACCOUNT_NOT_FOUND` | chưa có tài khoản TinoPage Builder cho dịch vụ: liên hệ hỗ trợ Tino | ## Hạn mức theo dịch vụ TinoPage Builder không bán theo gói cố định: hạn mức theo dịch vụ đã mua, nằm ở `config.effective` của [Tổng quan tài khoản](/docs/api/builder-get-overview). Đọc hạn mức từ API, đừng ghi cứng: số có thể đổi khi dịch vụ đổi. `-1` là không giới hạn. | Khoá | Áp cho | Nghĩa | | --- | --- | --- | | `sites` | tài khoản | số website (chưa xoá, kể cả nháp) | | `pages_per_site` | mỗi website | số trang | | `items_per_site` | mỗi website | số mặt hàng | | `domains_per_site` | mỗi website | số tên miền riêng | | `ai_generations_daily` | mỗi website | lượt AI tạo, sửa nội dung trong 24 giờ | | `ai_chat_daily` | mỗi website | tin nhắn với trợ lý AI trong 24 giờ | | `ai_images_daily` | mỗi website | ảnh AI trong 24 giờ | - Số đang dùng: `usage` của Tổng quan tài khoản (`sites`, `sites_paused`, `sites_published`) và `pages`, `items`, `domains` (`used`, `limit`) của từng website. - Hết số website: tạo website trả 409 `LIMIT_EXCEEDED`, `details.key` là `sites`; hết số tên miền: `domains_per_site`. - Sau khi hạ hạn mức hoặc dịch vụ chấm dứt, tài khoản giữ chạy các website cũ nhất trong số `sites`; website còn lại bị hệ thống tạm ngưng (`paused: true`, `paused_reason: over_limit`): trang công khai báo website tạm ngưng, không nhận liên hệ, đơn hàng. Nâng hạn mức hoặc xoá bớt website thì website tạm ngưng chạy lại, cũ nhất trước. Trang, mặt hàng, tên miền vượt hạn mức không bị xoá, chỉ không thêm mới được. - Dịch vụ tạm ngưng: chỉ đọc. Thao tác ghi trả 403 `ACCOUNT_SUSPENDED`; `GET` và vé đăng nhập vẫn dùng được (vào chỉ xem). Dịch vụ đã chấm dứt: thao tác ghi và vé đăng nhập trả 403 `ACCOUNT_TERMINATED`. ## Tạo website bằng AI [Tạo website bằng AI](/docs/api/builder-post-sites) nhận `intake`: thông tin cơ sở kinh doanh để AI chọn mẫu và viết nội dung. | Ô | Bắt buộc | Tối đa (ký tự) | Ghi chú | | --- | --- | --- | --- | | `business_name` | có | 120 | tên cơ sở | | `industry` | có | 80 | ngành nghề, vd tiệm bánh, spa, quán cà phê | | `phone` | có | 20 | số Việt Nam: đầu `0`, `84` hoặc `+84`, rồi 9 số di động (bắt đầu 3, 5, 7, 8, 9) hoặc 10 số cố định (bắt đầu 2); được có khoảng trắng, chấm, gạch, ngoặc | | `address` | — | 200 | địa chỉ | | `city` | — | 80 | tỉnh, thành phố | | `services` | — | 300 | dịch vụ, sản phẩm chính | | `hours` | — | 100 | giờ mở cửa | | `zalo` | — | 100 | số điện thoại hoặc đường dẫn Zalo | | `email` | — | 120 | email liên hệ | - Ô ngoài bảng, ô không phải chuỗi hoặc quá dài trả 400 `INVALID_REQUEST` (`details.field`: `intake` hoặc `intake.<ô>`). Thiếu ô bắt buộc, số điện thoại hay email sai trả 422 `VALIDATION_FAILED`, `details` theo `intake.<ô>` kèm lý do tiếng Việt. - Lượt tạo chạy nền 1–5 phút: lệnh tạo trả HTTP 202 với `state: running`. Hỏi [Tiến độ tạo website](/docs/api/builder-get-site-creation) vài giây một lần tới khi `state` là `done` (`site_id` là website mới) hoặc `failed` (`message` là lý do tiếng Việt). - Mỗi tài khoản một lượt tạo tại một thời điểm: lượt thứ hai trả 409 `CREATION_IN_PROGRESS`. Tính năng AI tạm dừng trả 503 `AI_UNAVAILABLE`. - Kết quả lượt tạo giữ 1 giờ; sau đó (hoặc khi máy chủ khởi động lại) Tiến độ tạo website trả `idle`, website đã tạo vẫn có ở [Danh sách website](/docs/api/builder-get-sites). - Tiến độ có thể có thêm `step` (`queued`, `design`, `write`, `images`, `build`) và `mode` (`design`, `merge`) khi xong: chỉ để hiện tiến độ, đừng rẽ nhánh theo hai khoá này. ## Đăng, tạm ngưng, xoá website | Trạng thái | Nghĩa | | --- | --- | | `status: draft` | chưa đăng: website mới tạo, hoặc đã tạm ngưng bằng [Tạm ngưng website](/docs/api/builder-post-sites-site-unpublish) | | `status: published` | đã đăng, chạy trên `host` (tên miền riêng) hoặc link xem thử `preview_url` | | `paused: true` | hệ thống tạm ngưng (`paused_reason: over_limit`: tài khoản vượt số website), đứng trên `status` | - [Đăng website](/docs/api/builder-post-sites-site-publish) đăng bản mới nhất, cũng là mở lại website đã tạm ngưng. Website `paused` trả 409 `SITE_PAUSED`: xoá bớt website khác hoặc nâng số website. - [Tạm ngưng website](/docs/api/builder-post-sites-site-unpublish) gỡ website khỏi mạng, nội dung giữ nguyên. - [Xoá website](/docs/api/builder-delete-sites-site) đưa website vào thùng rác (Tino khôi phục được theo yêu cầu qua hỗ trợ), gỡ tên miền riêng của website và trả lại một chỗ trong số website. - [Chi tiết website](/docs/api/builder-get-sites-site) có `todo`: số liên hệ chưa gọi lại (`leads_new`) và đơn hàng chưa xác nhận (`orders_new`). ## Tên miền riêng 1. Đăng website trước: website chưa đăng trả 409 `SITE_NOT_PUBLISHED`. 2. [Gắn tên miền riêng](/docs/api/builder-post-sites-site-domains) với `hostname` (vd `example.vn`, `banhang.example.vn`): trả 201, tên miền ở `status: pending` kèm `dns`, các bản ghi khách cần đặt ở nơi quản lý DNS của tên miền. 3. Khách đặt bản ghi: CNAME về `dns_target` (tên `@` và `www` với tên miền gốc, nhãn con với tên miền con) và TXT `_tino-verify` (giá trị `tino-site-verify=…`) chứng minh sở hữu. Tên bản ghi tính từ tên miền gốc. Lấy `dns_target` và giá trị TXT từ API, đừng ghi cứng. 4. TinoPage Builder tự kiểm lại tên miền `pending` theo lịch (`next_check_at`); [Kiểm tra lại DNS](/docs/api/builder-post-sites-site-domains-hostname-verify) kiểm ngay. Đủ CNAME và TXT thì `status` chuyển `active`, chứng chỉ HTTPS được cấp tự động (`ssl_status`: `pending`, `active`, `error`); `www` chuyển về tên miền gốc. - `cname_ok`, `txt_ok` là kết quả lần kiểm gần nhất; `error` nói thiếu gì (tiếng Việt), rỗng khi đạt. `checked_at` là `0001-01-01T00:00:00Z` khi chưa kiểm lần nào. - `owner_verified: true`: chủ tên miền đã được xác nhận, không cần TXT (`dns` chỉ còn CNAME). - Tự kiểm dừng sau 14 lần không đạt (khoảng 10 ngày); `error` ghi rõ, gọi Kiểm tra lại DNS để thử tiếp. - Hết số tên miền của website: 409 `LIMIT_EXCEEDED` (`details.key: domains_per_site`); tên miền đang gắn website khác: 409 `DOMAIN_TAKEN`; không phải tên miền: 422 `VALIDATION_FAILED` (`details.hostname`). ## Liên hệ và đơn hàng [Liên hệ và đơn hàng](/docs/api/builder-get-sites-site-leads) chỉ đọc: `kind=lead` (mặc định) là liên hệ từ biểu mẫu của website, `kind=order` là đơn hàng; mới trước, phân trang bằng `page`, `per_page` (mặc định 20, tối đa 50) kèm `meta`. | `status` | Nghĩa | Lọc được | | --- | --- | --- | | `moi` | mới | có | | `da_lien_he` | đã liên hệ (liên hệ) | có | | `xac_nhan` | đã xác nhận | có | | `dang_lam` | đang làm (đơn món) | không | | `san_sang` | sẵn sàng (đơn món) | không | | `dang_giao` | đang giao | có | | `hoan_tat` | hoàn tất | có | | `huy` | đã huỷ | có | - Liên hệ: `id`, `kind`, `name`, `phone`, `payload` (nội dung biểu mẫu, khoá tuỳ mẫu website), `source_page`, `status`, `created_at`. - Đơn hàng: `id`, `code`, `name`, `phone`, `address`, `note`, `items` (`name`, `option`, `qty`, `subtotal`), `shipping`, `total` (`null` khi website không ghi giá), `payment` (`COD`, `Chuyển khoản` hoặc chữ khác), `status`, `status_label` (nhãn tiếng Việt), `created_at`, `sheet_error` (lỗi gửi đơn sang Google Sheets, rỗng khi không có). - Trạng thái lạ: hiện `status_label` nếu có, không thì giữ nguyên `status`. ## Vé đăng nhập [Vé đăng nhập một lần](/docs/api/builder-post-login) mở TinoPage Builder đúng tài khoản của dịch vụ, không cần khách đăng nhập lại: - `target: me` (mặc định) vào trang quản lý; `target: editor` vào trình sửa của `site_id`. Không gửi `site_id`: website cũ nhất của tài khoản (tài khoản chưa có website thì vào trang quản lý). - Trả 201 `{url, expires_at}`: `url` là https trên máy chủ TinoPage Builder, dùng một lần, hiệu lực 120 giây. Mở ngay trong trình duyệt của chủ dịch vụ; không lưu, không gửi qua kênh khác. Ứng dụng chat tự xem trước link không làm mất vé. - `login_url` của Tổng quan tài khoản không phải vé: link mở trang đăng nhập TinoPage Builder bằng tài khoản Tino, khách tự đăng nhập. ## Gửi lại an toàn Mọi lệnh ghi (tạo website, đăng, tạm ngưng, xoá, gắn, kiểm, gỡ tên miền, vé đăng nhập) nhận `idempotency_key` (8–64 ký tự `A-Za-z0-9._:-`); với `DELETE`, gửi ở query. Tạo một khoá cho mỗi lần bấm của khách: - Mất kết nối giữa chừng thì gửi lại cùng khoá, cùng nội dung: nhận lại kết quả lần trước, lệnh không chạy lần hai. TinoPage Builder nhớ khoá 24 giờ; lần trước lỗi 5xx thì không nhớ, gửi lại sẽ chạy thật. - Cùng khoá mà nội dung khác, hoặc lần trước còn đang chạy: 409 `IDEMPOTENCY_CONFLICT`. Tải lại dữ liệu trước khi thử với khoá mới. - Không gửi khoá thì mỗi lần gọi là một lệnh mới. ## Câu trả lời Thành công: `{"data": …}`, `data` là câu trả lời của TinoPage Builder; danh sách có thêm `meta` (`page`, `per_page`, `total`, `last_page`). HTTP 200, 201 khi gắn tên miền và cấp vé đăng nhập, 202 khi nhận lệnh tạo website. Thời điểm theo RFC 3339; ID website là UUID. ## Lỗi ```json { "error": ["LIMIT_EXCEEDED"], "message": "Tài khoản đã dùng hết số website được phép. Nâng cấu hình dịch vụ trên Tino để tạo thêm website.", "details": { "key": "sites" }, "request_id": "…" } ``` Rẽ nhánh theo `error[0]`, không theo `message` (câu tiếng Việt, có thể đổi). Mã viết hoa; `invalid method` (route không có cho dịch vụ này) 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` | ID website, tên miền, query, body hoặc `idempotency_key` sai dạng, `details.field` chỉ trường: 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 | `ACCOUNT_SUSPENDED` | dịch vụ đang tạm ngưng: chặn thao tác ghi, `GET` vẫn dùng được | | 403 | `ACCOUNT_TERMINATED` | dịch vụ đã chấm dứt: chặn thao tác ghi và vé đăng nhập | | 404 | `SERVICE_NOT_FOUND`, `invalid method` | không phải dịch vụ TinoPage Builder của tài khoản đang đăng nhập: về danh sách dịch vụ | | 404 | `SERVICE_NOT_LINKED` | tài khoản TinoPage Builder gắn với dịch vụ khác: tìm lại dịch vụ ([Tìm dịch vụ TinoPage Builder](#tim-dich-vu-tinopage-builder)) | | 404 | `ACCOUNT_NOT_FOUND` | chưa có tài khoản TinoPage Builder: liên hệ hỗ trợ Tino | | 404 | `RESOURCE_NOT_FOUND` | website hoặc tên miền không có trong tài khoản (hoặc đã xoá): tải lại danh sách | | 409 | `LIMIT_EXCEEDED` | hết hạn mức của dịch vụ đã mua, `details.key` chỉ hạn mức: xoá bớt hoặc nâng dịch vụ | | 409 | `CREATION_IN_PROGRESS` | đang có lượt tạo website: chờ lượt đó xong | | 409 | `SITE_PAUSED` | website bị hệ thống tạm ngưng vì vượt số website: chưa đăng lại được | | 409 | `SITE_NOT_PUBLISHED` | đăng website trước rồi mới gắn tên miền riêng | | 409 | `DOMAIN_TAKEN` | tên miền đang gắn với một website khác | | 409 | `INVALID_ACTION` | không làm được ở trạng thái hiện tại, `message` nói lý do: tải lại rồi thử lại | | 409 | `IDEMPOTENCY_CONFLICT` | cùng `idempotency_key` mà nội dung khác, hoặc lần trước còn đang chạy | | 422 | `VALIDATION_FAILED` | dữ liệu sai: hiện lỗi dưới đúng trường theo `details` (`intake.<ô>`, `hostname`, `kind`, `status`, `target`) | | 429 | `RATE_LIMITED` | thao tác quá nhanh: thử lại sau ít giây | | 503 | `AI_UNAVAILABLE` | tính năng tạo website bằng AI tạm dừng: thử lại sau | | 500, 502, 503 | `INTERNAL_ERROR`, `NETWORK_ERROR`, `INVALID_RESPONSE`, `NOT_CONFIGURED` | kết nối giữa Tino và TinoPage Builder gián đoạn: lỗi phía Tino, không phải lỗi token. Đừng đăng xuất, thử lại sau | --- # Hồ sơ chủ thể tên miền Tên miền `.vn` đã thanh toán mà chủ thể chưa đủ thông tin hoặc chưa đủ hồ sơ (eKYC CCCD, bản khai của tổ chức) thì có đơn nhưng **chưa được đăng ký** với VNNIC: trạng thái `Pending`. Bốn route dưới đây cho phần mềm của khách xem tên miền nào đang chờ, còn thiếu gì, rồi sửa chủ thể; đủ hồ sơ thì Tino tự đăng ký tên miền. Cập nhật: 2026-10-27. Tên miền chưa hoàn tất hồ sơ **chưa được giữ chỗ**: người khác vẫn đăng ký được. Theo Thông tư 48/2025/TT-BKHCN, nguyên tắc "đăng ký trước được cấp trước" chỉ áp cho tên miền đã hoàn thành thủ tục và trả phí. Nên báo khách hoàn tất sớm. ## Route và quyền | Route | Việc | Quyền | | --- | --- | --- | | [`GET /v1/domains/pending`](/docs/api/get-domains-pending) | Tên miền chưa kích hoạt và việc còn phải làm | `domains:registrant` | | [`GET /v1/domains/{id}/registrant`](/docs/api/get-domains-id-registrant) | Chủ thể và tình trạng hồ sơ của một tên miền đang chờ | `domains:registrant` | | [`PUT /v1/domains/{id}/registrant`](/docs/api/put-domains-id-registrant) | Lưu chủ thể (khai mới hoặc dùng chủ thể của tên miền khác); Tino thử đăng ký ngay | `domains:registrant` | | [`GET /v1/registrants`](/docs/api/get-registrants) | Chủ thể của các tên miền đang chạy, để chọn lại | `domains:registrant` | Cả bốn route cần `domains:registrant` (Xem và hoàn tất hồ sơ chủ thể tên miền đang chờ đăng ký): quyền này chỉ có ở [token API cá nhân](/docs/personal-tokens) có giới hạn IP; ứng dụng OAuth và máy chủ MCP không bao giờ được quyền này. Route trả đủ dữ liệu chủ thể của chính khách (CCCD, ngày sinh, số điện thoại, địa chỉ): không ghi các trường này vào log. eKYC và nộp bản khai làm ở Client Area của Tino (tino.vn), không qua API. ## Tên miền đang chờ `GET /v1/domains/pending`, tên miền cũ trước: ```json { "domains": [ { "id": 200001, "name": "example.vn", "status": "Pending", "subject_type": "ind", "ready": false, "actions": [{ "code": "ekyc", "message": "Chủ thể cần eKYC CCCD trong tài khoản này" }], "reason": "Chưa eKYC CCCD 001******001" } ] } ``` | Trường | Nghĩa | | --- | --- | | `subject_type` | `ind` cá nhân · `org` tổ chức · `hkd` hộ kinh doanh | | `ready` | `true`: đủ hồ sơ, Tino đang đăng ký (vài phút) | | `actions` | việc khách còn phải làm (bảng dưới); rỗng mà `ready: false` là bản khai đã nộp, đang chờ Tino duyệt | | `reason` | lý do lần đăng ký gần nhất chưa được; có thể `null`. Số giấy tờ (dãy 9–13 chữ số) trong câu được che, chỉ giữ 3 số đầu và 3 số cuối | Không có tên miền nào: `{"domains": []}`. Tên miền đăng ký xong thì biến khỏi danh sách này và chuyển `Active` ở `GET /v1/domain`. ## Việc còn phải làm | `actions[].code` | Việc | | --- | --- | | `fields` | Thiếu hoặc sai các trường trong `fields` (ví dụ `["nationalid", "city"]`): sửa rồi `PUT` | | `owner_fields` | Như trên, cho chủ hộ của hộ kinh doanh | | `ekyc`, `owner_ekyc` | Chủ thể (hoặc chủ hộ) cần eKYC đúng CCCD đã khai, trong chính tài khoản này | | `ekyc_name`, `owner_ekyc_name` | Họ tên đã khai khác tên trên eKYC: sửa đúng như CCCD rồi `PUT` | | `ekyc_other_account`, `owner_ekyc_other_account` | CCCD đã eKYC ở tài khoản Tino khác: dùng chủ thể khác hoặc liên hệ Tino | | `declaration` | Tổ chức: nộp bản khai đã ký (hoặc ký số hồ sơ tổ chức) ở Client Area | ## Xem chủ thể `GET /v1/domains/{id}/registrant`: ```json { "domain": { "id": 200001, "name": "example.vn", "status": "Pending" }, "subject_type": "ind", "registrant": { "firstname": "Van A", "lastname": "Nguyen", "companyname": "", "taxid": "", "householdsid": "", "nationalid": "001090000001", "birthday": "1990-01-01", "gender": "M", "email": "user@example.com", "phonenumber": "0900000001", "country": "VN", "state": "Thành phố Hồ Chí Minh", "city": "Phường Bến Thành", "ward": "", "address1": "123 Example Street", "address2": "", "postcode": "", "position": "" }, "owner": null, "dossier": { "ekyc": "required", "declaration": "not_needed" }, "actions": [{ "code": "ekyc", "message": "Chủ thể cần eKYC CCCD trong tài khoản này" }], "reason": "Chưa eKYC CCCD 001******001", "ready": false } ``` - `state`, `city` là **tên** tỉnh / thành và phường / xã (danh mục sau sáp nhập), không phải mã. - `owner`: chủ hộ (họ tên, CCCD…) khi `subject_type` là `hkd`; VNNIC xét eKYC của chủ hộ. Loại khác: `null`. - `dossier.ekyc`: `ok` · `required` · `name_mismatch` · `other_account` · `not_needed` (tổ chức, đuôi không phải `.vn`). - `dossier.declaration` (tổ chức): `accepted` · `pending` (đã nộp, chờ duyệt) · `cancelled` (bị từ chối) · `none` · `not_needed`. `dossier.signature`: `ok` (đã ký số hồ sơ tổ chức theo mã số thuế) · `none`. ## Dùng lại chủ thể cũ `GET /v1/registrants` trả chủ thể của các tên miền **đang chạy** của khách, mới trước, mỗi người / tổ chức một dòng: ```json { "registrants": [ { "from_domain_id": 200002, "domain": "example.com.vn", "subject_type": "ind", "registrant": { "…": "như trên" }, "owner": null, "ready": true, "actions": [] } ] } ``` `ready: true`: chủ thể đã eKYC (hoặc đã ký số) trong tài khoản này, dùng cho tên miền mới là đăng ký được ngay. Tổ chức chỉ có bản khai giấy ở tên miền cũ thì `ready: false`, `actions` có `declaration`: bản khai gắn với từng tên miền, phải nộp lại. ## Lưu chủ thể `PUT /v1/domains/{id}/registrant`, body JSON, một trong hai dạng: ```json { "from_domain_id": 200002 } ``` ```json { "registrant": { "firstname": "Van A", "lastname": "Nguyen", "nationalid": "001090000001", "phonenumber": "0900000001", "state": "Thành phố Hồ Chí Minh", "city": "Phường Bến Thành", "address1": "123 Example Street", "email": "user@example.com", "birthday": "1990-01-01", "gender": "M", "country": "VN" }, "owner": null } ``` - Gửi **đủ các trường** của chủ thể: trường không gửi coi như để trống; trường lạ bị bỏ qua. - Bắt buộc với `.vn`: `firstname`, `lastname`, `nationalid`, `phonenumber`, `state`, `city`, `address1`; tổ chức thêm `companyname`, `taxid`; hộ kinh doanh thêm `householdsid` và `owner` (chủ hộ: `firstname`, `lastname`, `nationalid`). Đuôi khác: `firstname`, `lastname`, `email`, `phonenumber`, `address1`, `city`, `country`. - Lưu xong Tino thử đăng ký ngay và trả hồ sơ mới (cùng dạng `GET`); đọc lại `actions`, `ready` để biết bước tiếp theo. Không gọi lại thì hệ thống tự thử khoảng 5 phút một lần. - Chỉ dùng cho tên miền đang chờ. Đổi chủ thể tên miền đã `Active`: [`PUT /v1/domain/{id}/contact`](/docs/api/put-domain-id-contact). ## Lỗi Lỗi dạng `{"error": [""]}`, hiện thẳng cho khách được. | HTTP | Câu | Khi nào | | --- | --- | --- | | 403 | `insufficient_scope` | token thiếu quyền `domains:registrant` (token của ứng dụng OAuth, hoặc token cá nhân không chọn quyền này) | | 404 | Không tìm thấy tên miền chờ đăng ký | tên miền đã `Active`, đã huỷ, hoặc không phải của khách | | 422 | Tên miền không tồn tại hoặc đã kích hoạt | `PUT` vào tên miền không còn chờ | | 422 | Thiếu city (… các trường) | thiếu trường bắt buộc | | 422 | Trường state không hợp lệ | giá trị không phải chuỗi hoặc dài quá 255 ký tự | | 422 | Hộ kinh doanh cần thông tin chủ hộ (owner) | hộ kinh doanh thiếu `owner` | | 422 | Không dùng được chủ thể của tên miền #N | `from_domain_id` không phải tên miền đang chạy của khách | --- # Đăng nhập bằng Tino — OAuth 2.0 và OpenID Connect Ứng dụng của bạn đăng nhập khách bằng tài khoản Tino và gọi API Tino thay khách qua OAuth 2.0 Authorization Code + PKCE (S256), kèm OpenID Connect. Issuer là `https://api.tino.vn`; trang đăng nhập và đồng ý là `https://auth.tino.vn/oauth/consent`. Cập nhật: 2026-10-27. Nguồn sự thật cho endpoint, quyền và claim: tài liệu discovery `https://api.tino.vn/.well-known/openid-configuration`. ## Tổng quan Mọi endpoint đều có trong tài liệu discovery: đọc `https://api.tino.vn/.well-known/openid-configuration` (hoặc `/.well-known/oauth-authorization-server`, cùng nội dung) thay vì ghi cứng địa chỉ. | Mục | Giá trị | | --- | --- | | Issuer (`iss`) | `https://api.tino.vn` | | Trang đăng nhập + đồng ý (`authorization_endpoint`) | `https://auth.tino.vn/oauth/consent` | | Đổi code, làm mới token (`token_endpoint`) | `POST https://api.tino.vn/oauth/token` | | Thu hồi token (`revocation_endpoint`) | `POST https://api.tino.vn/oauth/revoke` | | UserInfo (`userinfo_endpoint`) | `GET https://api.tino.vn/oauth/userinfo` | | Khoá công khai (`jwks_uri`) | `GET https://api.tino.vn/oauth/jwks` | | Gọi API thay khách (`resource_gateway`) | `https://api.tino.vn/v1/` | | Đăng ký ứng dụng (`registration_endpoint`) | `POST https://api.tino.vn/oauth/register` — client công khai tự đăng ký, xem [Đăng nhập từ CLI](/docs/cli-login) | | Xin mã thiết bị (`device_authorization_endpoint`) | `POST https://api.tino.vn/oauth/device_authorization` — CLI, xem [Đăng nhập từ CLI](/docs/cli-login) | | Luồng hỗ trợ | `response_type=code`; `grant_type` = `authorization_code`, `refresh_token`, `urn:ietf:params:oauth:grant-type:device_code` | | PKCE | bắt buộc, chỉ `S256` | | Xác thực client ở token endpoint | `client_secret_post` (client có secret) hoặc `none` (client công khai + PKCE); không hỗ trợ HTTP Basic | | Ký ID token | `RS256` | Không có implicit flow, hybrid flow, client credentials hay password grant. ## Luồng đăng nhập 1. Ứng dụng chuyển trình duyệt của khách tới `https://auth.tino.vn/oauth/consent` kèm `client_id`, `scope`, `code_challenge`. 2. Khách đăng nhập (nếu chưa), chọn tài khoản (nếu trình duyệt có từ hai tài khoản), đồng ý cấp quyền. 3. Tino chuyển trình duyệt về `redirect_uri` của ứng dụng với `?code=…&state=…`. 4. Ứng dụng gọi `POST https://api.tino.vn/oauth/token` với `code` + `code_verifier`. 5. Tino trả `access_token`, `id_token` (khi có `openid`), `refresh_token` (khi có `offline_access`). 6. Ứng dụng gọi `https://api.tino.vn/v1/` với `Authorization: Bearer `. Trình duyệt chỉ mang `code` về ứng dụng; ứng dụng tự gọi api.tino.vn để đổi code lấy token, kèm `code_verifier` chứng minh cùng một lượt đăng nhập. ## Đăng ký ứng dụng Tino tạo ứng dụng cho bạn và cấp `client_id` (cùng `client_secret` nếu ứng dụng có server). Client công khai (CLI, ứng dụng chạy trên máy khách, MCP client) cũng tự đăng ký được qua `POST https://api.tino.vn/oauth/register` (RFC 7591), xem [Đăng nhập từ CLI](/docs/cli-login). | Loại client | Dùng khi | Xác thực ở `/oauth/token` | | --- | --- | --- | | Confidential (có `client_secret`) | Ứng dụng web đổi code ở server | `client_id` + `client_secret` trong body form (`client_secret_post`) + PKCE | | Public (không secret) | Ứng dụng chạy trên máy khách: SPA, mobile, CLI | chỉ `client_id` + PKCE | Khi xin ứng dụng, gửi Tino: tên và logo (https) hiện trên trang đồng ý, danh sách redirect URI, các quyền cần (mục Gọi API của Tino), và ứng dụng có giữ được secret ở server không. Quy tắc redirect URI: - So khớp nguyên chuỗi với URI đã đăng ký (kể cả đường dẫn và query); không nhận URI có `#fragment`. - Phải là `https://`. Riêng khi phát triển trên máy: `http://localhost` hoặc `http://127.0.0.1`. - URI loopback đăng ký không kèm cổng khớp với mọi cổng (RFC 8252 mục 7.3), hợp cho ứng dụng CLI nghe cổng ngẫu nhiên. `client_id` có thể là URL của một Client ID Metadata Document (discovery báo `client_id_metadata_document_supported: true`), nhưng chỉ các URL Tino đã đăng ký trước mới được nhận. ## Bước 1 — Chuyển khách tới trang đồng ý Ứng dụng tạo `code_verifier`, `state`, `nonce` ngẫu nhiên cho mỗi lần đăng nhập, giữ chúng (cookie httpOnly hoặc session), rồi chuyển trình duyệt tới `https://auth.tino.vn/oauth/consent` kèm các tham số trên query. | Tham số | Bắt buộc | Giá trị | | --- | --- | --- | | `response_type` | có | `code` | | `client_id` | có | client_id Tino cấp | | `redirect_uri` | có | đúng nguyên chuỗi đã đăng ký | | `scope` | có | các quyền cách nhau dấu cách, trong số quyền ứng dụng được cấp; `openid` để có ID token, `offline_access` để có refresh token | | `state` | nên có | chuỗi ngẫu nhiên chống CSRF; Tino trả nguyên về | | `code_challenge` | có | `BASE64URL(SHA256(code_verifier))`, không dấu `=` | | `code_challenge_method` | có | `S256` | | `nonce` | nên có (OpenID) | chuỗi ngẫu nhiên tối đa 255 ký tự; có lại trong ID token | | `prompt` | không | `none`: khách đã đăng nhập và đã cấp đủ quyền thì chuyển về ngay, không dừng ở màn nào | Ví dụ: ```text https://auth.tino.vn/oauth/consent?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.example.com%2Fauth%2Fcallback&scope=openid%20profile%20email%20offline_access%20services%3Aread&state=af0ifjsldkj&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&nonce=n-0S6_WzA2Mj ``` Tạo PKCE (Node.js 18+): ```javascript import { createHash, randomBytes } from "node:crypto"; const codeVerifier = randomBytes(32).toString("base64url"); // 43 ký tự const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url"); ``` Trên trang đồng ý, khách chưa đăng nhập thì đăng nhập trước (OTP, passkey, Google, Zalo, GitHub). Trình duyệt có từ hai tài khoản Tino trở lên thì khách chọn tài khoản. Khách đã cấp đủ các quyền này cho ứng dụng thì không phải đồng ý lại; xin thêm quyền thì hỏi lại. Kết quả, Tino chuyển trình duyệt về `redirect_uri`: | Tình huống | Query về `redirect_uri` | | --- | --- | | Khách bấm Cho phép | `code=…&state=…` | | Khách bấm Từ chối | `error=access_denied&state=…` | | `scope` lạ hoặc ngoài quyền của ứng dụng | `error=invalid_scope&state=…` | | `client_id` không có hoặc bị tắt, `redirect_uri` chưa đăng ký | không chuyển về: trang của Tino báo lỗi | Trước khi dùng `code`, so `state` nhận được với `state` đã giữ; khác nhau thì bỏ. ## Bước 2 — Đổi code lấy token Đổi `code` trong 60 giây, mỗi code dùng một lần: `POST https://api.tino.vn/oauth/token`, body `application/x-www-form-urlencoded`. Client confidential gọi từ server và gửi `client_secret` trong body; không dùng header `Authorization: Basic`. ```bash curl -X POST https://api.tino.vn/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d grant_type=authorization_code \ -d code=AUTH_CODE \ -d redirect_uri=https://app.example.com/auth/callback \ -d client_id=YOUR_CLIENT_ID \ -d client_secret=YOUR_CLIENT_SECRET \ -d code_verifier=CODE_VERIFIER ``` | Tham số | Giá trị | | --- | --- | | `grant_type` | `authorization_code` | | `code` | code nhận ở `redirect_uri` | | `redirect_uri` | đúng URI đã gửi ở bước 1 | | `client_id` | client_id của bạn | | `client_secret` | chỉ client confidential | | `code_verifier` | chuỗi gốc đã tạo `code_challenge` | Câu trả lời (HTTP 200): ```json { "access_token": "tinoat_…", "token_type": "Bearer", "expires_in": 86400, "scope": "openid profile email offline_access services:read", "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6…", "refresh_token": "tinort_…" } ``` | Token | Có khi | Thời hạn mặc định | | --- | --- | --- | | `access_token` (`tinoat_…`, chuỗi mờ, không phải JWT) | luôn có | 86400 giây (24 giờ) | | `id_token` (JWT RS256) | `scope` có `openid` | 86400 giây (24 giờ) | | `refresh_token` (`tinort_…`) | `scope` có `offline_access` | 2592000 giây (30 ngày) | | `code` | — | 60 giây, dùng một lần | Thời hạn do Tino cấu hình và có thể đổi: đọc `expires_in` của mỗi câu trả lời thay vì ghi cứng. Giữ token ở server (hoặc kho bảo mật của thiết bị), không đưa vào URL hay localStorage. ## Làm mới và thu hồi token Mỗi lần làm mới trả một refresh token mới và vô hiệu hoá cái cũ (xoay vòng). Dùng lại một refresh token đã xoay thì Tino thu hồi toàn bộ quyền của ứng dụng trên tài khoản đó; khách phải đăng nhập và đồng ý lại. ```bash curl -X POST https://api.tino.vn/oauth/token \ -d grant_type=refresh_token \ -d refresh_token=tinort_… \ -d client_id=YOUR_CLIENT_ID \ -d client_secret=YOUR_CLIENT_SECRET ``` - `scope` (không bắt buộc): thu hẹp quyền của token mới; vượt quyền đã cấp thì `invalid_scope` và refresh token cũ vẫn dùng được. - Câu trả lời cùng dạng bước 2. Lưu ngay `refresh_token` mới trước khi dùng `access_token`. - Nhiều tiến trình cùng làm mới một refresh token: chỉ một lần thắng, lần kia bị coi là dùng lại. Gom việc làm mới về một chỗ (khoá theo tài khoản). - `invalid_grant` khi làm mới: token hết hạn, đã thu hồi hoặc khách đã thu hồi quyền ứng dụng. Đưa khách đăng nhập lại từ bước 1. Thu hồi khi khách đăng xuất khỏi ứng dụng (RFC 7009): `POST https://api.tino.vn/oauth/revoke` với `token=`, `client_id`, `client_secret` (client confidential). Refresh token và access token đi kèm cùng hết hiệu lực; endpoint luôn trả HTTP 200. Khách cũng tự thu hồi được ở trang Ứng dụng được cấp quyền (`https://auth.tino.vn/me/apps`); token của ứng dụng hết hiệu lực ngay, lần gọi sau nhận 401 `invalid_token`. ## ID token và UserInfo ID token là JWT ký `RS256`; kiểm chữ ký bằng khoá có `kid` trùng header, lấy từ `https://api.tino.vn/oauth/jwks` (lưu cache, tải lại khi gặp `kid` lạ). Dùng thư viện OpenID Connect có sẵn (openid-client, jose, Authlib…) thay vì tự viết. | Claim | Có khi | Kiểm hoặc dùng | | --- | --- | --- | | `iss` | luôn có | phải là `https://api.tino.vn` | | `aud`, `azp` | luôn có | phải là client_id của bạn | | `exp`, `iat` | luôn có | còn hạn | | `nonce` | đã gửi `nonce` ở bước 1 | phải trùng giá trị đã giữ | | `auth_time` | khi Tino biết | lúc khách đăng nhập (unix giây) | | `sub` | luôn có | mã khách hàng Tino (chuỗi): khoá để gắn tài khoản trong ứng dụng của bạn | | `email` | scope `email` | email của tài khoản (hoặc của liên hệ phụ khi khách đăng nhập bằng tài khoản liên hệ) | | `given_name`, `family_name`, `name` | scope `profile` | tên, họ, họ tên | Ghép tài khoản theo `sub`, không theo `email`: khách đổi được email. UserInfo trả cùng các claim (`sub` và các claim theo scope), cần access token có `openid`: ```bash curl https://api.tino.vn/oauth/userinfo -H "Authorization: Bearer tinoat_…" ``` ```json { "sub": "26", "email": "binh@example.com", "given_name": "Bình", "family_name": "Trần", "name": "Bình Trần" } ``` Access token thiếu `openid` thì nhận 403 `insufficient_scope`. ## Gọi API của Tino Ứng dụng gọi API Tino thay khách qua gateway `https://api.tino.vn/v1/` với `Authorization: Bearer `. Mỗi route thuộc một quyền; route ngoài quyền của token trả 403 `insufficient_scope`. ```bash curl https://api.tino.vn/v1/details -H "Authorization: Bearer tinoat_…" ``` `GET /v1/details` chạy route `GET /details` của UserAPI bằng tài khoản của khách; body và câu trả lời giữ nguyên dạng của UserAPI. | Quyền (`scope`) | Khách thấy trên trang đồng ý | Ví dụ route | Số route | | --- | --- | --- | --- | | `openid` | Xác thực danh tính của bạn | ID token, `/oauth/userinfo` | — | | `profile` | Họ tên | claim `name`, `given_name`, `family_name` | — | | `email` | Địa chỉ email | claim `email` | — | | `offline_access` | Duy trì truy cập khi bạn không trực tuyến | có `refresh_token` | — | | `profile:read` | Xem thông tin tài khoản | `GET /v1/details`, `GET /v1/contacts` | 11 | | `profile:write` | Sửa thông tin tài khoản | `PUT /v1/notifications/@id/ack` | 1 | | `services:read` | Xem dịch vụ, gồm cả thông tin đăng nhập dịch vụ | `GET /v1/service`, `GET /v1/service/@id` | 28 | | `services:write` | Quản lý dịch vụ của bạn | `POST /v1/service/@id/renew`, `POST /v1/service/@id/vms/@vmid/reboot` | 14 | | `domains:read` | Xem tên miền | `GET /v1/domain`, `GET /v1/domain/@id` | 17 | | `domains:write` | Đăng ký, gia hạn và quản lý tên miền | `POST /v1/domain/@id/renew`, `POST /v1/domain/@id/reg` | 12 | | `dns:read` | Xem bản ghi DNS | `GET /v1/dns`, `GET /v1/domain/@id/dns` | 7 | | `dns:write` | Sửa bản ghi DNS | `POST /v1/domain/@id/dns`, `DELETE /v1/domain/@id/dns/@index` | 10 | | `billing:read` | Xem hoá đơn và thanh toán | `GET /v1/invoices`, `GET /v1/balance` | 13 | | `billing:write` | Thanh toán, nạp tiền | `POST /v1/addfunds` | 7 | | `orders:write` | Đặt mua dịch vụ: giỏ hàng, báo giá, tạo đơn (trả bằng số dư cần thêm quyền Thanh toán) | `POST /v1/quote`, `POST /v1/carts`, `POST /v1/order` | 8 | | `tickets:read` | Xem ticket hỗ trợ | `GET /v1/tickets`, `GET /v1/tickets/@number` | 9 | | `tickets:write` | Tạo và trả lời ticket | `POST /v1/tickets`, `POST /v1/tickets/@number` | 4 | Quyền của dịch vụ (gateway `/v1` mở từ 27/10/2026): gọi `https://api.tino.vn/v1/service///…` cho dịch vụ của chính khách. | Quyền (`scope`) | Khách thấy trên trang đồng ý | Route | Hướng dẫn | | --- | --- | --- | --- | | `tinopay:read` | Xem TinoPay: tài khoản nhận tiền, giao dịch, webhook | 16 | [Bắt đầu với TinoPay](/docs/tinopay-start) | | `tinopay:write` | Quản lý TinoPay: tài khoản ảo, webhook, thông báo, tích hợp Sapo | 21 | [Bắt đầu với TinoPay](/docs/tinopay-start) | | `builder:read` | Xem website TinoPage Builder | 6 | [Bắt đầu với TinoPage Builder](/docs/builder-start) | | `builder:write` | Quản lý website TinoPage Builder: tạo, đăng, tên miền riêng | 7 | [Bắt đầu với TinoPage Builder](/docs/builder-start) | | `waf:read` | Xem website được TinoWAF bảo vệ và nhật ký sự kiện | 8 | [TinoWAF](/docs/waf) | | `waf:write` | Quản lý TinoWAF: website, mức bảo vệ, máy chủ gốc, luật IP | 11 | [TinoWAF](/docs/waf) | `tinopay:owner` (tạo API token TinoPay, liên kết tài khoản ngân hàng nhận tiền) như `domains:owner`: chỉ token API cá nhân có giới hạn IP. Xin ít quyền nhất đủ dùng: khách thấy từng dòng trên trang đồng ý. `domains:owner` (lấy mã EPP, đổi chủ thể tên miền) và `domains:registrant` ([hồ sơ chủ thể tên miền đang chờ](/docs/domain-registrant)) chỉ dành cho [token API cá nhân](/docs/personal-tokens); ứng dụng không bao giờ được cấp. Ba lệnh đặt đơn có thể trừ số dư (`POST /v1/carts/{uuid}/confirm`, `POST /v1/order`, `POST /v1/order/{product_id}`) cần cả `orders:write` và `billing:write`. Từng route, tham số, ví dụ request và response: [Gọi API Tino](/docs/api). ## Lỗi thường gặp `/oauth/token` và `/oauth/revoke` trả lỗi dạng `{"error": "", "error_description": ""}`. `/oauth/userinfo` và gateway `/v1` kèm header `WWW-Authenticate: Bearer error=""`. | Endpoint | HTTP | `error` | Nguyên nhân | Xử lý | | --- | --- | --- | --- | --- | | `/oauth/token` | 401 | `invalid_client` | sai `client_id` hoặc `client_secret`, ứng dụng bị tắt | kiểm cấu hình; không gửi secret qua HTTP Basic | | `/oauth/token` | 400 | `invalid_grant` | code sai, hết 60 giây, đã dùng, khác `redirect_uri` hoặc `code_verifier`; quyền đã bị thu hồi | cho khách đăng nhập lại từ bước 1 | | `/oauth/token` (refresh) | 400 | `invalid_grant` | refresh token hết hạn, đã thu hồi hoặc đã dùng lại (cả quyền bị thu hồi) | cho khách đăng nhập lại | | `/oauth/token` (refresh) | 400 | `invalid_scope` | `scope` thu hẹp vượt quyền đã cấp | refresh token cũ vẫn dùng được | | `/oauth/token` | 400 | `unsupported_grant_type` | `grant_type` khác `authorization_code` và `refresh_token` | — | | `/oauth/userinfo`, `/v1/*` | 401 | `invalid_token` | access token sai, hết hạn hoặc khách đã thu hồi quyền | làm mới token; vẫn 401 thì đăng nhập lại | | `/oauth/userinfo`, `/v1/*` | 403 | `insufficient_scope` | token không có quyền của route (UserInfo: thiếu `openid`) | xin thêm quyền ở bước 1 | | `/v1/*` | 403 | `ipnotallowed` | IP gọi API đang bị Tino chặn | liên hệ Tino | | trang đồng ý | — | `access_denied` (về `redirect_uri`) | khách bấm Từ chối | báo khách, cho thử lại | | trang đồng ý | — | `invalid_scope` (về `redirect_uri`) | scope lạ hoặc ngoài quyền của ứng dụng | sửa `scope` | Lỗi nghiệp vụ của từng route `/v1/*` (ví dụ dịch vụ không tồn tại) giữ nguyên câu trả lời của UserAPI, thường là HTTP 200 kèm `{"error": [""]}`. ## Tham khảo - [OpenID discovery của Tino](https://api.tino.vn/.well-known/openid-configuration): endpoint, quyền, claim đang chạy trên production - [Protected resource metadata](https://api.tino.vn/.well-known/oauth-protected-resource) (RFC 9728): cho client MCP; xem [Kết nối Claude, ChatGPT với Tino (MCP)](/docs/mcp) - [JWKS](https://api.tino.vn/oauth/jwks): khoá công khai kiểm ID token - [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749) OAuth 2.0 - [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636) PKCE - [RFC 7009](https://www.rfc-editor.org/rfc/rfc7009) thu hồi token - [RFC 8252](https://www.rfc-editor.org/rfc/rfc8252) ứng dụng native - [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) --- # 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//tinopay/…` | | Xác thực | `Authorization: Bearer `: 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//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//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/` | `service.ptype` | `"tinopaypanel"` | 2. Khi mở phần quản lý, gọi [Thông tin merchant](/docs/api/tinopay-get-merchant) (`GET /service//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 `), 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. --- # Bắt đầu với Tino Uptime Tino Uptime kiểm website, máy chủ, cổng dịch vụ, bản ghi DNS, chứng chỉ SSL và hạn tên miền từ các điểm dò ở Việt Nam và quốc tế. Khi đích lỗi, Tino Uptime mở sự cố và báo qua email, Telegram, Discord, Slack, webhook hoặc Zalo. API của dịch vụ cho ứng dụng của bạn quản lý monitor, đọc uptime, kết quả kiểm, sự cố và kênh cảnh báo của gói Tino Uptime. Cập nhật: 2026-10-24. Nguồn: module Tino Uptime của Tino và OpenAPI của Tino Uptime. ## Gọi API | Mục | Giá trị | | --- | --- | | Địa chỉ | `https://api.tino.vn/service//uptime/…` | | Xác thực | `Authorization: Bearer `: token đăng nhập của chủ dịch vụ Tino Uptime | | Body | JSON, `Content-Type: application/json` | | Từng route | mục Tino Uptime ở [API Reference](/docs/reference#tino-uptime) | - Body luôn là JSON. Với [Sửa monitor](/docs/api/uptime-put-monitors-monitor), chỉ gửi trường cần đổi. - Chỉ các tham số ghi ở từng route được chuyển tiếp. Tino Uptime từ chối trường lạ trong body (422 `validation_failed`). - ID monitor, sự cố, kênh trong đường dẫn là UUID; sai dạng trả 400 `invalid_request`. - Phần chưa có trong API này (trang trạng thái, máy chủ, WordPress, cảnh báo CVE) mở ở bảng điều khiển Tino Uptime bằng `login_url` của [Tổng quan gói](/docs/api/uptime-get-overview). Gateway `/v1` chưa mở các route Tino Uptime: token ứng dụng (`tinoat_`) và [token API cá nhân](/docs/personal-tokens) (`tinopat_`) chưa gọi được. Token đăng nhập là token khách dùng ở khu vực khách hàng tino.vn; [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/100002/uptime/monitors", query={"state": "down"})) ``` `100002` là ID dịch vụ Tino Uptime: cách tìm ở mục dưới. ## Tìm dịch vụ Tino Uptime Mỗi tài khoản Tino có một tài khoản Tino Uptime; gói đang dùng gắn với đúng một dịch vụ. 1. Nhận diện bằng module của dịch vụ: [Chi tiết dịch vụ](/docs/api/get-service-id) (`GET https://api.tino.vn/service/`, cùng token đăng nhập) có `service.acc_module` là `"tino_uptime"`. Danh sách ứng viên lấy ở [Danh sách dịch vụ](/docs/api/get-service). 2. Gọi [Tổng quan gói](/docs/api/uptime-get-overview) (`GET /service//uptime`): | Kết quả | Nghĩa | | --- | --- | | 200 | gói Tino Uptime đang dùng của khách: gọi các route khác với ID này | | 404 `service_not_linked` | dịch vụ không còn là gói đang dùng (khách đã chuyển sang dịch vụ khác): thử dịch vụ Tino Uptime kế tiếp | | 404 `invalid method` | dịch vụ không phải Tino Uptime hoặc không tồn tại | | 404 `service_not_found` | dịch vụ của tài khoản khác | | 404 `account_not_found` | chưa có tài khoản Tino Uptime cho dịch vụ: liên hệ hỗ trợ Tino | ## Hạn mức gói Hạn mức nằm ở `subscription.limits` của [Tổng quan gói](/docs/api/uptime-get-overview), số đang dùng ở [Mức dùng](/docs/api/uptime-get-usage). Đọc hạn mức từ API, đừng ghi cứng: số của từng gói có thể đổi. | Trường | Nghĩa | | --- | --- | | `max_monitors` | số monitor tối đa | | `min_interval_s` | chu kỳ kiểm ngắn nhất (giây) | | `raw_retention_days` | số ngày xem được kết quả kiểm từng lượt | | `locations` | vị trí dò được dùng: `vn-cmc`, `vn-vt` (Việt Nam), `intl` (quốc tế) | | `channels` | loại kênh cảnh báo được tạo | Vượt hạn mức trả 403 `entitlement_exceeded`; `details.resource` chỉ hạn mức (`monitors`, `min_interval_s`, `locations`, `channels`). Khi dịch vụ bị tạm ngưng, tài khoản Tino Uptime chỉ đọc được: thao tác ghi trả 403 `account_suspended`. Sau khi hạ gói, monitor vượt hạn mức bị dừng (`disabled_reason: paused_by_plan`, đếm ở `monitors_paused_by_plan`). ## Loại monitor [Tạo monitor](/docs/api/uptime-post-monitors) nhận `name`, `interval_s` (30–86400 giây, không dưới `limits.min_interval_s`), `locations` và `settings`. `settings.type` quyết định các trường còn lại: | `type` | Bắt buộc | Tuỳ chọn | | --- | --- | --- | | `http` | `url` | `method` (`GET`, `HEAD`, `POST`), `expected_status` (mảng mã HTTP, tối đa 20), `follow_redirects` (mặc định `true`), `max_latency_ms` (1–60000), `headers` (object), `body` (tối đa 4096 ký tự), `basic_auth` (`username`, `password`) | | `keyword` | `url`, `keyword` (1–100 ký tự) | `mode` (`present`, `absent`), `case_sensitive`, `method` (`GET`, `POST`) và các tuỳ chọn còn lại của `http` | | `ssl` | `host` | `port` (443, 465, 993, 995), `warn_days` (1–90, mặc định 14) | | `domain` | `domain` | `warn_days` (1–120, mặc định 30) | | `ping` | `host` | — | | `tcp` | `host`, `port` (1–65535) | — | | `dns` | `name`, `record_type` (`A`, `AAAA`, `CNAME`, `MX`, `NS`, `TXT`) | `expected` (mảng giá trị, tối đa 20), `resolver` (IP hoặc IP kèm cổng 53; bỏ trống thì hỏi máy chủ tên miền có thẩm quyền) | | `heartbeat` | — | `grace_s` (0–86400, mặc định 300) | - `heartbeat` đảo chiều: hệ thống của bạn gọi `settings.ping_url` sau mỗi lần chạy. `ping_url` chỉ có trong câu trả lời của lệnh tạo: lưu lại ngay. - Header, body, mật khẩu Basic auth không bao giờ được trả lại; `settings` chỉ cho biết `header_names`, `body_set`, `basic_auth_set`. - `international_critical: true`: chỉ điểm dò quốc tế lỗi cũng tính là down (mặc định `false`). - Đích nội bộ hoặc không an toàn bị từ chối: 422 `validation_failed` với `details.reason: blocked_destination`. Một đích bị kiểm quá dày (tính cả khách khác) trả 422 `target_rate_exceeded`: chọn chu kỳ dài hơn. `state` của monitor: `pending` (chưa có kết quả), `up`, `suspect`, `down`, `partial`, `down_international`, `paused` (monitor đã tắt, bị hệ thống dừng theo `disabled_reason`, hoặc đang trong `paused_until`). ## Kênh cảnh báo [Tạo kênh](/docs/api/uptime-post-channels) với `kind` trong `limits.channels` của gói; kênh mới chờ xác minh (trừ email tới đúng địa chỉ đã xác minh của chủ tài khoản). Kênh chưa có `opted_in_at` không nhận tin. | `kind` | `config` | Xác minh (`verification.method`) | | --- | --- | --- | | `email` | `address` | `email_code`: gửi mã trong thư tới [Xác minh kênh](/docs/api/uptime-post-channels-channel-verify) (`code`); mã hiệu lực 24 giờ | | `telegram` | — | `telegram_link`: mở `telegram_url` (hoặc `telegram_group_url` cho nhóm) trong 10 phút | | `discord`, `slack`, `webhook` | `url` (https) | `test_message`: gọi Xác minh kênh để gửi tin thử; gửi được thì kênh được xác minh | | `zalo` | `consent: true`; `phone` để xác minh bằng OTP, bỏ `phone` để liên kết qua OA | `zalo_otp` hoặc `zalo_link` (gửi `zalo_link_code` vào OA ở `zalo_oa_url`, hiệu lực 10 phút) | - Kênh webhook trả `webhook_secret` (`whsec_…`) chỉ một lần, trong câu trả lời của lệnh tạo: lưu lại để kiểm chữ ký tin gửi tới. - Thư mã xác minh: tối đa 5 thư mỗi giờ mỗi tài khoản, 3 thư mỗi ngày mỗi địa chỉ; vượt trả 429 `rate_limited`. Mã sai trả 422 `token_invalid`. - [Gửi tin thử](/docs/api/uptime-post-channels-channel-test) chỉ cho kênh đã xác minh và đang bật; còn lại trả 409 `conflict`. ## Danh sách và gửi lại an toàn Danh sách (monitor, sự cố, kênh, kết quả kiểm từng lượt) phân trang bằng con trỏ: gửi `next_cursor` của trang trước vào `cursor`; `next_cursor` là `null` khi hết. `limit` mặc định 50, tối đa 100 (kết quả kiểm từng lượt: mặc định 100, tối đa 1000). ```json { "data": { "data": [], "next_cursor": null } } ``` [Tạo monitor](/docs/api/uptime-post-monitors) và [Tạo kênh](/docs/api/uptime-post-channels) nhận `idempotency_key` (8–128 ký tự `A-Za-z0-9._:-`). Mất kết nối giữa chừng thì gửi lại đúng body với cùng khoá: lệnh không tạo thêm. Cùng khoá mà body khác, hoặc lần gửi trước còn đang chạy, trả 409 `idempotency_conflict`. Không gửi khoá thì mỗi lần gọi là một lệnh mới: đọc lại danh sách trước khi thử lại. ## Câu trả lời Thành công: `{"data": …}`, `data` là câu trả lời của Tino Uptime. HTTP 200, 201 khi tạo, 202 khi đã xếp tin thử, 204 khi xoá (không có nội dung). Thời điểm theo RFC 3339; ID là UUID. ## Lỗi ```json { "error": ["entitlement_exceeded"], "message": "Đã vượt hạn mức của gói.", "details": { "resource": "monitors" }, "request_id": "…" } ``` Rẽ nhánh theo `error[0]`, không theo `message` (câu tiếng Việt, có thể đổi). Với `validation_failed`, `details.field` chỉ trường sai, `details.reason` chỉ lý do khi có. Lỗi Tino trả trước khi chuyển tiếp (`service_not_found`, `invalid method`) 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` | ID sai dạng (không phải UUID), `idempotency_key` sai dạng, hoặc yêu cầu sai: 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 | `account_suspended` | tài khoản Tino Uptime đang tạm ngưng: chặn thao tác ghi, `GET` vẫn dùng được | | 403 | `entitlement_exceeded` | vượt hạn mức gói, `details.resource` chỉ hạn mức: nâng gói hoặc bớt monitor, kênh | | 404 | `service_not_found`, `invalid method` | không phải dịch vụ Tino Uptime của tài khoản đang đăng nhập: về danh sách dịch vụ | | 404 | `service_not_linked` | dịch vụ không còn là gói đang dùng: tìm lại dịch vụ ([Tìm dịch vụ Tino Uptime](#tim-dich-vu-tino-uptime)) | | 404 | `account_not_found` | chưa có tài khoản Tino Uptime: liên hệ hỗ trợ Tino | | 404 | `not_found` | monitor, sự cố, kênh không có hoặc đã xoá: tải lại danh sách | | 409 | `conflict` | không làm được ở trạng thái hiện tại (vd gửi tin thử tới kênh chưa xác minh): tải lại rồi thử lại | | 409 | `idempotency_conflict` | cùng `idempotency_key` mà body khác, hoặc lần trước còn đang chạy | | 422 | `validation_failed` | dữ liệu sai: hiện lỗi dưới đúng trường theo `details.field` | | 422 | `target_rate_exceeded` | đích bị kiểm quá dày (tính cả khách khác): chọn chu kỳ dài hơn | | 422 | `token_invalid` | mã xác minh kênh email sai hoặc hết hạn | | 429 | `rate_limited` | thao tác quá nhanh: thử lại sau | | 502, 503 | `network`, `invalid_response`, `not_configured`, `unavailable` | kết nối giữa Tino và Tino Uptime gián đoạn: lỗi phía Tino, không phải lỗi token. Đừng đăng xuất, thử lại sau | --- # Kết nối Claude, ChatGPT với Tino (MCP) Tino Connector cho trợ lý AI (Claude, ChatGPT, ứng dụng MCP khác) làm việc với tài khoản Tino: xem và quản lý dịch vụ hosting, VPS, tên miền, bản ghi DNS, hoá đơn và ticket bằng câu lệnh thường, chỉ trong phạm vi quyền khách đồng ý. Kết nối dùng chuẩn MCP (Model Context Protocol) và đăng nhập OAuth: trợ lý không bao giờ thấy mật khẩu hay mã OTP của khách. Cập nhật: 2026-10-27. Mã nguồn máy chủ MCP: kho công khai [tinovn/tino-connector-mcp](https://github.com/tinovn/tino-connector-mcp). ## Tổng quan | Mục | Giá trị | | --- | --- | | Máy chủ MCP | `https://api.tino.vn/mcp` | | Giao thức | MCP Streamable HTTP: mỗi `POST` một thông điệp JSON-RPC, trả JSON (không SSE, không phiên); `GET` trả 405 | | Phiên bản giao thức | `2025-06-18`, `2025-03-26`, `2024-11-05` | | Xác thực | `Authorization: Bearer `: token OAuth ([Đăng nhập bằng Tino](/docs/oauth)) hoặc [token API cá nhân](/docs/personal-tokens) | | Metadata cho client (RFC 9728) | `https://api.tino.vn/.well-known/oauth-protected-resource` | | Tự đăng ký client (RFC 7591) | `POST https://api.tino.vn/oauth/register` (`registration_endpoint` trong `https://api.tino.vn/.well-known/oauth-authorization-server`) | | Plugin Claude Code | marketplace `tinovn/tino-connector-mcp`, plugin `tino@tinovn` | ## Kết nối ### Claude (web, Desktop, điện thoại) 1. Mở Claude, vào **Customize → Connectors**, bấm **Add custom connector**. 2. Tên: `Tino`; URL: `https://api.tino.vn/mcp`. 3. Phần xác thực để mặc định (đăng nhập OAuth); không cần nhập client ID hay header. 4. Bấm **Connect**: trang đăng nhập Tino mở ra (mục [Đăng nhập và cấp quyền](#dang-nhap-va-cap-quyen)). Tuỳ gói Claude, quản trị viên của tổ chức có thể phải bật connector trước. ### Claude Code Cài plugin `tino`: ```bash claude plugin marketplace add tinovn/tino-connector-mcp ``` ```bash claude plugin install tino@tinovn ``` Trong Claude Code gõ `/mcp`, chọn `tino`, bấm **Authenticate**. Không dùng plugin thì thêm thẳng máy chủ MCP rồi cũng `/mcp` → **Authenticate**: ```bash claude mcp add --transport http tino https://api.tino.vn/mcp ``` Claude Code không tự đăng ký client: nó nhận diện bằng Client ID Metadata Document (`client_id=https://claude.ai/oauth/claude-code-client-metadata`). Mặc định Claude Code xin đủ các quyền máy chủ MCP liệt kê, gồm cả quyền ghi; muốn quyền hẹp hơn thì dùng token API cá nhân (mục [Ứng dụng MCP khác](#ung-dung-mcp-khac-cursor-vs-code-n8n)). ### ChatGPT Tài khoản ChatGPT bật chế độ nhà phát triển (Developer mode) thêm được connector MCP tuỳ chỉnh: URL `https://api.tino.vn/mcp`, xác thực OAuth. Đường bấm cụ thể tuỳ phiên bản giao diện ChatGPT. ### Ứng dụng MCP khác (Cursor, VS Code, n8n…) **Cách chính: đăng nhập OAuth.** Client MCP hỗ trợ OAuth theo đặc tả MCP tự đăng ký với Tino rồi mở trang đăng nhập; chỉ cần khai URL `https://api.tino.vn/mcp`, không cần client ID, khoá bí mật hay header: 1. Gọi `https://api.tino.vn/mcp` khi chưa có token thì nhận HTTP 401; header `WWW-Authenticate` chỉ tới metadata `https://api.tino.vn/.well-known/oauth-protected-resource`. 2. Client đọc discovery `https://api.tino.vn/.well-known/oauth-authorization-server` và tự đăng ký qua `registration_endpoint` (`POST https://api.tino.vn/oauth/register`, RFC 7591): client công khai (`token_endpoint_auth_method: none`), redirect về `http://localhost` hoặc `127.0.0.1` (mọi cổng) hay `https://`. Quy tắc từng trường ở [Đăng nhập từ CLI](/docs/cli-login#dang-ky-ung-dung). 3. Client mở trang đăng nhập Tino (Authorization Code + PKCE, xem [Đăng nhập bằng Tino](/docs/oauth)); khách đồng ý như mục [Đăng nhập và cấp quyền](#dang-nhap-va-cap-quyen). Trên trang Ứng dụng được cấp quyền, ứng dụng tự đăng ký hiện bằng tên nó khai (`client_name`). **Cách thay thế: token API cá nhân.** Dùng khi ứng dụng không hỗ trợ OAuth của MCP, chạy trên máy chủ không mở được trình duyệt, hoặc cần quyền hẹp hơn, giới hạn IP: 1. Tạo token ở `https://auth.tino.vn/me/security`, mục **Token API**: chọn đúng quyền cần dùng; ứng dụng chạy trên máy chủ cố định thì nên giới hạn IP. Xem [Token API cá nhân](/docs/personal-tokens). 2. Khai máy chủ MCP trong ứng dụng: URL `https://api.tino.vn/mcp`, header `Authorization: Bearer `. Dạng cấu hình JSON phổ biến: ```json { "mcpServers": { "tino": { "type": "http", "url": "https://api.tino.vn/mcp", "headers": { "Authorization": "Bearer tinopat_…" } } } } ``` Token là chìa khoá tài khoản: không dán vào khung chat, không commit lên Git; lộ thì thu hồi ngay ở trang Token API. ## Đăng nhập và cấp quyền Khi kết nối, trình duyệt mở trang Tino: khách đăng nhập như thường (mã OTP qua email hoặc số điện thoại, Google, Zalo hoặc passkey), xem danh sách quyền ứng dụng xin rồi bấm **Đồng ý**. Ứng dụng nhận access token có hạn (mặc định 24 giờ) và refresh token để tự gia hạn; refresh token không dùng quá hạn (mặc định 30 ngày) thì phải kết nối lại. Đồng ý là cấp toàn bộ quyền trong danh sách. Muốn quyền hẹp hơn, dùng token API cá nhân chỉ với các quyền cần thiết. ## Quyền và tool Mỗi tool là một route của gateway `/v1` (xem [Gọi API Tino](/docs/api)); mô tả tool kết thúc bằng route và quyền, ví dụ `GET /details · scope profile:read`. `tools/list` chỉ trả các tool token gọi được, nên trợ lý không thấy tool ngoài quyền đã cấp. | Quyền (nhãn trên trang đồng ý) | Trợ lý làm được | | --- | --- | | Xem thông tin tài khoản | Hồ sơ (đã lược giấy tờ, số điện thoại, địa chỉ, thuế, ngân hàng), thông báo | | Sửa thông tin tài khoản | Đánh dấu thông báo đã đọc | | Xem dịch vụ, gồm cả thông tin đăng nhập dịch vụ | Danh sách, chi tiết dịch vụ và VPS, tài nguyên, chứng chỉ SSL; **có thể gồm mật khẩu đăng nhập dịch vụ** | | Quản lý dịch vụ của bạn | Bật, tắt, khởi động lại VPS, đổi hostname, gia hạn, đặt mua chứng chỉ SSL | | Xem tên miền | Thông tin tên miền, nameserver, khoá chuyển, tự gia hạn | | Quản lý tên miền của bạn | Đổi nameserver, đặt mua, gia hạn, bật/tắt khoá, chuyển tiếp | | Xem bản ghi DNS | Đọc vùng và bản ghi DNS | | Sửa bản ghi DNS | Thêm, sửa, xoá vùng và bản ghi DNS | | Xem hoá đơn và thanh toán | Hoá đơn, số dư, lịch sử giao dịch | | Thanh toán, nạp tiền | Thanh toán hoá đơn bằng **số dư tài khoản Tino**, tạo yêu cầu nạp tiền | | Xem ticket hỗ trợ | Xem ticket | | Tạo và trả lời ticket | Tạo, trả lời, đóng, mở lại ticket | | Xem TinoPay: tài khoản nhận tiền, giao dịch, webhook | Thông tin merchant, tài khoản ngân hàng, tài khoản ảo, giao dịch và thống kê, webhook và nhật ký gửi, ứng dụng thông báo, cấu trúc mã thanh toán, tích hợp Sapo và nhật ký đối soát | | Quản lý TinoPay: tài khoản ảo, webhook, thông báo, tích hợp Sapo | Tạo, bật, tắt, xoá tài khoản ảo; thêm, sửa, xoá webhook, gửi lại webhook; ứng dụng thông báo Telegram, Zalo, Lark; tích hợp Sapo; sửa merchant, cấu trúc mã thanh toán | | Xem website TinoPage Builder | Tổng quan dịch vụ, danh sách và chi tiết website, trạng thái lượt tạo website, tên miền riêng, liên hệ và đơn hàng | | Quản lý website TinoPage Builder: tạo, đăng, tên miền riêng | Tạo website bằng AI, đăng, tạm ngưng, xoá website; thêm, kiểm tra DNS, gỡ tên miền riêng | | Xem website được TinoWAF bảo vệ và nhật ký sự kiện | Tổng quan dịch vụ, website, tên miền và bản ghi DNS cần trỏ, máy chủ gốc, nhật ký và tóm tắt sự kiện, danh sách IP chặn, cho phép | | Quản lý TinoWAF: website, mức bảo vệ, máy chủ gốc, luật IP | Thêm, xoá website; đổi mức bảo vệ, bật, tắt chống tấn công khẩn cấp; thêm, gỡ tên miền, kiểm tra DNS; sửa máy chủ gốc; chặn, cho phép IP | | Duy trì truy cập khi bạn không trực tuyến | Giữ kết nối (tự gia hạn access token) | Tool có quyền đọc mang chú thích `readOnlyHint: true`; tool có quyền ghi mang `destructiveHint: true`. Tool chuyển tiếp email, chuyển hướng tên miền, đăng ký nameserver riêng và lấy nội dung thanh toán của cổng thanh toán mang thêm `openWorldHint: true` (tác động ra hệ thống bên ngoài). ## Không làm được qua MCP - **Huỷ dịch vụ:** chỉ làm trên bảng điều khiển khách hàng Tino; MCP không có tool huỷ, kể cả khi token có quyền quản lý dịch vụ. - **Lấy mã chuyển tên miền (EPP), đổi chủ thể tên miền:** không bao giờ cấp cho Claude, ChatGPT hay ứng dụng OAuth nào. Chỉ token API cá nhân chọn quyền `domains:owner` (bắt buộc giới hạn IP) mới có hai tool này; chỉ chọn quyền đó khi thật cần. - **Tạo API token TinoPay, liên kết tài khoản ngân hàng nhận tiền:** cũng vậy, chỉ token API cá nhân chọn quyền `tinopay:owner` (bắt buộc giới hạn IP) mới có các tool này. - **Đặt mua hosting, VPS mới:** chưa hỗ trợ. Đặt mua tên miền và chứng chỉ SSL thì được. ## Ví dụ câu lệnh - "Liệt kê dịch vụ Tino của tôi và ngày gia hạn." - "Tên miền example.vn đang dùng nameserver nào?" - "Thêm bản ghi A `www` trỏ về 203.0.113.10 cho example.vn." - "Tôi còn hoá đơn nào chưa thanh toán?" - "Khởi động lại VPS có hostname web01." (thao tác ghi: trợ lý nên hỏi xác nhận trước) ## An toàn và dữ liệu - Mọi thao tác thay đổi (đặt hàng, gia hạn, thanh toán, đổi DNS hoặc nameserver, khởi động lại VPS) được đánh dấu là thao tác ghi; máy chủ MCP cũng dặn trợ lý nêu rõ việc sẽ làm và chờ khách đồng ý. Bước hỏi xác nhận do Claude, ChatGPT làm theo cài đặt của ứng dụng: nên giữ chế độ hỏi trước khi chạy và đọc kỹ nội dung trước khi đồng ý. - Trợ lý chỉ đọc, ghi qua API của Tino trong phạm vi quyền đã cấp; kết quả gửi về Claude hoặc ChatGPT để trả lời khách. - Máy chủ MCP lọc các trường định danh khỏi mọi bản ghi người (đối tượng có `email` kèm `firstname`, `lastname` hoặc `name`: tài khoản, liên hệ, chủ thể tên miền) trước khi gửi cho trợ lý: số giấy tờ, ngày sinh, giới tính, số điện thoại, địa chỉ, mã số thuế, mã hộ kinh doanh, ngân hàng, liên kết Zalo, IP và lần đăng nhập. Gọi thẳng gateway `/v1` thì câu trả lời giữ nguyên (xem [Gọi API Tino](/docs/api#du-lieu-ca-nhan)). - [Chính sách bảo mật](https://tino.vn/chinh-sach-bao-mat) · [Điều khoản sử dụng](https://tino.vn/dieu-khoan-su-dung-dich-vu). ## Thu hồi quyền Khách vào `https://auth.tino.vn/me/apps` (Ứng dụng được cấp quyền), bấm Thu hồi ở "Claude", "Claude Code", "ChatGPT" hoặc tên ứng dụng MCP đã tự đăng ký: mọi token của ứng dụng đó hết hiệu lực ngay. Token API cá nhân thu hồi ở `https://auth.tino.vn/me/security`, mục Token API. ## Xử lý sự cố | Hiện tượng | Cách xử lý | | --- | --- | | Claude Code báo cần xác thực (Needs authentication) | Gõ `/mcp`, chọn `tino`, bấm **Authenticate** | | Kết nối được một thời gian rồi phải đăng nhập lại | Kết nối lại: lâu không dùng thì refresh token hết hạn, hoặc khách đã thu hồi quyền | | Trang đăng nhập Tino báo ứng dụng không hợp lệ | Gửi ảnh chụp màn hình cho support@tino.vn | | Ứng dụng MCP khác không đăng nhập được | Ứng dụng phải hỗ trợ OAuth của MCP (tự đăng ký client); không hỗ trợ, hoặc chạy trên máy chủ không mở được trình duyệt, thì dùng token API cá nhân (mục Ứng dụng MCP khác) | | Tự đăng ký báo `429 too_many_requests` | Mỗi IP đăng ký tối đa 10 lần mỗi giờ: client nên lưu `client_id` đã đăng ký để dùng lại | | Dùng token cá nhân mà trợ lý không thấy tool cần dùng | Token thiếu quyền đó: tạo token mới đủ quyền | | Trợ lý báo `insufficient_scope` | Tool không áp dụng cho tài nguyên đó với quyền đã cấp, ví dụ lệnh VPS trên gói hosting | | HTTP 403 `ip_not_allowed` | Token cá nhân có giới hạn IP, đang gọi từ IP khác | | Không thấy lệnh huỷ dịch vụ | Đúng thiết kế: huỷ trên bảng điều khiển Tino | ## Cho nhà phát triển client MCP Gọi thử bằng token API cá nhân (`$TINO_TOKEN`). Mỗi thông điệp là một `POST` JSON-RPC 2.0; không token hoặc token sai thì HTTP 401 kèm header `WWW-Authenticate: Bearer error="invalid_token", scope="…", resource_metadata="https://api.tino.vn/.well-known/oauth-protected-resource"` để client bắt đầu OAuth. ```bash curl -X POST https://api.tino.vn/mcp \ -H "Authorization: Bearer $TINO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' ``` Gọi một tool: tham số đường dẫn của route là đối số bắt buộc; đối số khác đi vào query (`GET`, `DELETE`) hoặc body (`POST`, `PUT`). ```bash curl -X POST https://api.tino.vn/mcp \ -H "Authorization: Bearer $TINO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "service_details", "arguments": {"id": "100001"}}}' ``` - Phương thức hỗ trợ: `initialize`, `ping`, `tools/list`, `tools/call`; thông điệp không có `id` (notification) nhận HTTP 202. - Kết quả `tools/call` là câu trả lời của route: JSON dạng `text`, `isError: true` khi route báo lỗi (HTTP 4xx, 5xx hoặc có trường `error`); file (ví dụ PDF hoá đơn) trả dạng `resource` nhúng base64. - Tên tool viết thường nối gạch dưới (`get_details`, `service_details`, `dns_add_record`…) và có thể đổi khi API thêm route; lấy danh sách bằng `tools/list` thay vì ghi cứng. --- # Token API cá nhân Token API cá nhân cho phần mềm của chính khách (module WHMCS, script quản lý tên miền, công cụ riêng…) gọi API Tino mà không cần đăng nhập. Khách tự tạo token ở Tino ID, chọn quyền, hạn dùng và IP được gọi; phần mềm gửi token trong header `Authorization: Bearer tinopat_…` tới gateway `https://api.tino.vn/v1/`. Cập nhật: 2026-10-27. ## Khi nào dùng | Bạn cần | Dùng | | --- | --- | | Phần mềm của chính bạn gọi API bằng tài khoản Tino của bạn | Token API cá nhân (`tinopat_`) | | Ứng dụng của bạn phục vụ nhiều khách Tino, mỗi khách tự đăng nhập và đồng ý | [Đăng nhập bằng Tino](/docs/oauth) (`tinoat_`) | | Claude, ChatGPT làm việc với tài khoản Tino của bạn | [Kết nối MCP](/docs/mcp): đăng nhập OAuth, không cần token | | Ứng dụng MCP khác (Cursor, VS Code, n8n…) | [Kết nối MCP](/docs/mcp#ung-dung-mcp-khac-cursor-vs-code-n8n): đăng nhập OAuth (ứng dụng tự đăng ký); token API cá nhân khi ứng dụng không hỗ trợ OAuth của MCP hoặc chạy trên máy chủ không mở được trình duyệt | Chỉ token API cá nhân mới mang được quyền `domains:owner` (lấy mã EPP, đổi chủ thể tên miền); ứng dụng OAuth không bao giờ được cấp quyền này. ## Tạo token 1. Đăng nhập Tino ID, mở `https://auth.tino.vn/me/security`, mục **Token API**, bấm **Tạo token**. 2. Đặt tên token (1–64 ký tự), ví dụ "Module WHMCS". 3. Chọn quyền: ít nhất một quyền trong bảng dưới. Chọn quyền ghi của một nhóm thì giao diện chọn kèm quyền đọc cùng nhóm. 4. Chọn hạn dùng: 30 ngày, 90 ngày, 1 năm (mặc định) hoặc không hết hạn. 5. Giới hạn IP (không bắt buộc, trừ khi chọn `domains:owner`): các địa chỉ IPv4, IPv6 hoặc dải CIDR, cách nhau dấu cách hoặc dấu phẩy, tối đa 20. Để trống: gọi được từ mọi IP. 6. Chép token ngay: token chỉ hiện một lần, khi vừa tạo. Tino chỉ lưu bản băm SHA-256; danh sách token chỉ còn 4 ký tự cuối để nhận ra. Mỗi tài khoản đăng nhập có tối đa 20 token. Token có dạng `tinopat_` + 43 ký tự (base64url). | Quyền | Cho phép | | --- | --- | | `profile:read` | Xem thông tin tài khoản | | `profile:write` | Sửa thông tin tài khoản | | `services:read` | Xem dịch vụ, gồm cả thông tin đăng nhập dịch vụ | | `services:write` | Quản lý dịch vụ | | `domains:read` | Xem tên miền | | `domains:write` | Đăng ký, gia hạn và quản lý tên miền | | `domains:owner` | Lấy mã chuyển tên miền (EPP) và đổi chủ thể tên miền; bắt buộc giới hạn IP | | `domains:registrant` | Xem và hoàn tất hồ sơ chủ thể tên miền đang chờ đăng ký (có CCCD, ngày sinh); bắt buộc giới hạn IP | | `dns:read` | Xem bản ghi DNS | | `dns:write` | Sửa bản ghi DNS | | `billing:read` | Xem hoá đơn và thanh toán | | `billing:write` | Thanh toán, nạp tiền | | `orders:write` | Đặt mua dịch vụ: giỏ hàng, báo giá, tạo đơn (trả bằng số dư cần thêm quyền Thanh toán) | | `tickets:read` | Xem ticket hỗ trợ | | `tickets:write` | Tạo và trả lời ticket | | `tinopay:read` | Xem TinoPay: tài khoản nhận tiền, giao dịch, webhook | | `tinopay:write` | Quản lý TinoPay: tài khoản ảo, webhook, thông báo, tích hợp Sapo | | `tinopay:owner` | Tạo API token TinoPay và liên kết tài khoản ngân hàng nhận tiền; bắt buộc giới hạn IP | | `builder:read` | Xem website TinoPage Builder | | `builder:write` | Quản lý website TinoPage Builder: tạo, đăng, tên miền riêng | | `waf:read` | Xem website được TinoWAF bảo vệ và nhật ký sự kiện | | `waf:write` | Quản lý TinoWAF: website, mức bảo vệ, máy chủ gốc, luật IP | Mỗi quyền mở một nhóm route; xem route của từng quyền ở [Gọi API Tino](/docs/api). ## `domains:owner` và giới hạn IP `domains:owner` mở [lấy mã EPP](/docs/api/get-domain-id-epp) (`GET /v1/domain/@id/epp`), [đổi liên hệ, chủ thể tên miền](/docs/api/put-domain-id-contact) (`PUT /v1/domain/@id/contact`) Bốn route [hồ sơ chủ thể của tên miền đang chờ](/docs/domain-registrant) có quyền riêng `domains:registrant`, cũng chỉ token cá nhân có giới hạn IP. Ai có hai route của `domains:owner` có thể chuyển tên miền đi nơi khác, nên token mang `domains:owner` bắt buộc khai danh sách IP: Tino từ chối tạo token khi danh sách trống. Token lộ ra ngoài cũng không chuyển được tên miền từ máy khác. Gọi từ IP ngoài danh sách, mọi route của token đều trả 403 `ip_not_allowed`. ## Gọi API ```bash curl https://api.tino.vn/v1/domain -H "Authorization: Bearer tinopat_…" ``` Token gọi API như chính tài khoản đã tạo nó, chỉ trong các quyền đã chọn. Body, tham số và câu trả lời của từng route xem ở [API Reference](/docs/reference). Giữ token như mật khẩu: để trong biến môi trường hoặc kho bí mật của server, không đưa vào mã nguồn, URL hay trình duyệt. ## Theo dõi và thu hồi Danh sách token ở `https://auth.tino.vn/me/security` hiện tên, quyền, IP được gọi, lúc tạo, lần dùng gần nhất (cập nhật tối đa mỗi phút một lần) và hạn dùng. Token hết hạn hiện nhãn **Hết hạn**. Bấm **Thu hồi** để xoá token: phần mềm đang dùng nó nhận 401 `invalid_token` ngay ở lần gọi sau. Muốn đổi quyền, hạn dùng hay IP, tạo token mới rồi thu hồi token cũ. ## Lỗi | HTTP | `error` | Nguyên nhân | Xử lý | | --- | --- | --- | --- | | 401 | `invalid_token` | token sai, hết hạn hoặc đã thu hồi | tạo token mới | | 403 | `ip_not_allowed` | gọi từ IP ngoài danh sách giới hạn của token | gọi từ IP đã khai, hoặc tạo token với danh sách IP mới | | 403 | `insufficient_scope` | token không có quyền của route | tạo token có thêm quyền | | 403 | `ipnotallowed` | IP gọi API đang bị Tino chặn | liên hệ Tino | Khi tạo token, Tino báo lỗi nếu tên trống hoặc quá 64 ký tự, không chọn quyền nào, hạn dùng không hợp lệ, có IP hay dải IP sai (hoặc quá 20), chọn `domains:owner` mà không khai IP, hoặc đã đủ 20 token. --- # Môi trường thử nghiệm Tino chưa có môi trường thử nghiệm (sandbox) riêng cho API: mọi route chạy trên tài khoản, dịch vụ và tiền thật của khách. Trang này là cách thử an toàn trong điều kiện đó. Cập nhật: 2026-10-21. ## Thử với token chỉ có quyền đọc Khi khám phá API, tạo [token API cá nhân](/docs/personal-tokens) chỉ gồm các quyền `…:read` cần dùng, hạn 30 ngày, giới hạn IP của máy đang thử. Route ghi khi đó trả 403 `insufficient_scope` thay vì làm thay đổi thật. ```bash curl https://api.tino.vn/v1/service -H "Authorization: Bearer $TINO_TOKEN" ``` Thu hồi token ngay khi thử xong, ở `https://auth.tino.vn/me/security`. ## Route ghi tác động thật | Thao tác | Hệ quả thật | | --- | --- | | Đặt mua, gia hạn tên miền, dịch vụ, chứng chỉ SSL | tạo đơn và hoá đơn | | Thanh toán bằng số dư, trả hoá đơn bằng số dư | trừ tiền trong tài khoản | | Nạp tiền | tạo hoá đơn nạp tiền | | Đổi nameserver, sửa, xoá bản ghi DNS | website, email của tên miền đổi theo sau khi DNS lan truyền | | Bật, tắt, khởi động lại, reset VPS | dịch vụ trên VPS gián đoạn | | Tạo, trả lời ticket | nhân viên Tino nhận và xử lý | Thử thao tác DNS trên một tên miền hoặc vùng không dùng cho website thật, hoặc dùng bản ghi `TXT` có tên riêng rồi xoá đi. ## Xem trước khi làm - `GET /v1/service/@id/methods`: các thao tác dịch vụ hỗ trợ, trước khi gọi. - `POST /v1/service/@id/upgrade` không kèm `send=true`: chỉ tính giá nâng cấp, chưa gửi yêu cầu. - `POST /v1/domain/lookup`: kiểm tra tên miền còn trống và giá, trước khi đặt mua. ## Chạy test không chạm tài khoản thật Dựng mock server từ [OpenAPI](/openapi.json) (ví dụ bằng Prism hoặc công cụ OpenAPI khác): các route có mẫu response trọn vẹn được gắn làm `example`. Test của ứng dụng gọi mock; chỉ bước kiểm tra cuối mới gọi API thật với token quyền đọc. ## Trợ lý AI qua MCP Khi nối Claude, ChatGPT với Tino qua [MCP](/docs/mcp), giữ chế độ hỏi trước khi chạy thao tác ghi và đọc kỹ nội dung trước khi đồng ý. --- # Nhận webhook TinoPay Mỗi giao dịch vào (hoặc ra) tài khoản ngân hàng đã liên kết, TinoPay gửi một request `POST` tới URL webhook của bạn; body JSON là dữ liệu giao dịch, header mang token của webhook để bạn xác minh. Đây là cách nên dùng cho luồng cần xác nhận thanh toán tức thời (cổng thanh toán, nạp tiền tự động, xác nhận đơn hàng), thay vì gọi API hỏi lặp. Cập nhật: 2026-10-25. Nguồn: [tài liệu webhook của TinoPay](https://pay.tino.vn/docs/webhooks) và tài liệu TinoPay API v1. ## Luồng hoạt động 1. Khách chuyển khoản vào tài khoản ngân hàng đã kết nối với TinoPay. 2. TinoPay ghi nhận giao dịch (tiền vào hoặc tiền ra). 3. TinoPay gửi `POST` kèm dữ liệu giao dịch (JSON) tới URL của từng webhook khớp điều kiện. 4. Máy chủ của bạn trả HTTP 2xx: TinoPay đánh dấu thành công. Không thì TinoPay gửi lại, xem [Phản hồi và thử lại](#phan-hoi-va-thu-lai). ## Tạo webhook - Trên web TinoPay: menu Tích hợp → Webhooks → Thêm webhook; nút Tạo ngẫu nhiên sinh token 50 ký tự. - Bằng API merchant: route [Tạo webhook](/docs/api/tinopay-post-webhooks) (xem [Bắt đầu với TinoPay](/docs/tinopay-start) để gọi API). | Trường | Bắt buộc | Ý nghĩa | | --- | --- | --- | | `name` | có | tên webhook, tối đa 250 ký tự | | `bank_account_id` | có | tài khoản ngân hàng cần theo dõi | | `url` | có | URL nhận webhook, tối đa 250 ký tự; nên dùng HTTPS | | `event` | có | sự kiện kích hoạt, bảng dưới | | `token` | không | chuỗi xác minh; qua API bỏ trống thì tự sinh 50 ký tự | | `virtual_accounts` | không | mảng số tài khoản ảo của tài khoản ngân hàng đó; đặt thì webhook chỉ chạy cho giao dịch vào các tài khoản ảo này, để trống: mọi tài khoản ảo | | `skip_if_no_code` | không | `true`: bỏ qua giao dịch không trích được mã thanh toán | | `status` | không | `active` (mặc định), `inactive`; chỉ webhook đang hoạt động mới được gửi | | `event` | Kích hoạt khi | | --- | --- | | `in` | giao dịch tiền vào (credit): nhận tiền, dùng để xác nhận thanh toán | | `out` | giao dịch tiền ra (debit) | | `all` | mọi giao dịch, cả vào lẫn ra | Đa số tích hợp thanh toán chỉ cần `in` (mặc định trên web). Tạo được nhiều webhook cho nhiều tài khoản ngân hàng, nhiều hệ thống khác nhau. ## Request TinoPay gửi `POST` tới `url` của webhook, body JSON, kèm token của webhook ở hai header cùng giá trị: ```http POST /your-webhook-endpoint HTTP/1.1 Content-Type: application/json Authorization: Apikey ALLPAY-TOKEN: ``` | Header | Giá trị | | --- | --- | | `Content-Type` | `application/json` | | `Authorization` | `Apikey ` | | `ALLPAY-TOKEN` | ``: tên header TinoPay đang gửi, giữ nguyên | Kiểm một trong hai header là đủ; nên dùng `Authorization`. ```json { "transaction_id": "20261020083338000006", "gateway": "BIDV", "transactionDate": "2026-10-20 08:33:38", "accountNumber": "96240000001", "code": "DH12345", "content": "DH12345 chuyen tien mua hang", "transferType": "in", "transferAmount": 150000, "referenceCode": "0551dTCO-82LiomOss", "virtualAccount": "9624QA01" } ``` | Trường | Kiểu | Ý nghĩa | | --- | --- | --- | | `transaction_id` | string \| null | mã giao dịch tại TinoPay | | `gateway` | string | mã ngân hàng nguồn, ví dụ `BIDV` | | `transactionDate` | string (`Y-m-d H:i:s`) | thời điểm giao dịch | | `accountNumber` | string | số tài khoản ngân hàng nhận hoặc phát sinh giao dịch | | `code` | string \| null | mã thanh toán trích từ nội dung chuyển khoản theo cấu trúc mã của bạn; `null` nếu không trích được | | `content` | string | nội dung chuyển khoản, nguyên văn từ ngân hàng | | `transferType` | string | `in` tiền vào, `out` tiền ra | | `transferAmount` | int | số tiền (VND) | | `referenceCode` | string \| null | mã tham chiếu của ngân hàng (core reference) | | `virtualAccount` | string \| null | số tài khoản ảo nhận tiền; `null` nếu giao dịch không đi qua tài khoản ảo | `code` giúp khớp giao dịch với đơn hàng: đặt nội dung chuyển khoản là mã đơn (ví dụ [tạo mã QR](/docs/tinopay-api#tao-ma-vietqr) với `memo=DH12345`), TinoPay tự trích mã đó vào `code`. Cấu trúc mã khai ở web TinoPay (Cài đặt → Cấu trúc mã thanh toán) hoặc qua `pay_codes` của [Sửa thông tin merchant](/docs/api/tinopay-patch-merchant). ## Xác minh và xử lý Webhook công khai trên Internet nên phải kiểm mỗi request có đúng do TinoPay gửi. TinoPay dùng token chung (shared token), không ký HMAC; token đi trong header dạng nguyên văn, nên URL webhook luôn phải là HTTPS. 1. So token trong header `Authorization` (bỏ tiền tố `Apikey `) với token của webhook bằng phép so sánh thời gian hằng; khác thì trả 401 và bỏ qua request. 2. Chống trùng theo `transaction_id` (hoặc `referenceCode`): một giao dịch có thể đến nhiều lần (thử lại, gửi lại thủ công). Đã xử lý thì bỏ qua nhưng vẫn trả 200. 3. Kiểm `transferType` để chỉ xử lý đúng chiều tiền cần. 4. Đối chiếu `transferAmount` với đơn hàng tìm theo `code`, `virtualAccount` hoặc `content` trước khi đánh dấu đã thanh toán. 5. Trả 2xx ngay khi nhận, việc nặng đưa vào hàng đợi. Node.js (18+), không thư viện ngoài: ```javascript import { createServer } from "node:http"; import { timingSafeEqual } from "node:crypto"; const token = Buffer.from(process.env.TINOPAY_WEBHOOK_TOKEN); const seen = new Set(); // môi trường thật: lưu transaction_id vào cơ sở dữ liệu const valid = (header) => { const got = Buffer.from(String(header ?? "").replace(/^Apikey /, "")); return got.length === token.length && timingSafeEqual(got, token); }; createServer((req, res) => { if (req.method !== "POST" || !valid(req.headers.authorization)) return res.writeHead(401).end(); let raw = ""; req.on("data", (chunk) => (raw += chunk)).on("end", () => { const tx = JSON.parse(raw); if (!seen.has(tx.transaction_id)) { seen.add(tx.transaction_id); // ghi nhận thanh toán: tx.code, tx.transferAmount, tx.virtualAccount } res.writeHead(200).end("ok"); }); }).listen(3000); ``` PHP: ```php . Có máy chủ (Apache + PHP-FPM) không chuyển header Authorization cho PHP: // khi đó đọc header ALLPAY-TOKEN, cùng giá trị. $auth = $_SERVER["HTTP_AUTHORIZATION"] ?? ""; $got = substr($auth, 0, 7) === "Apikey " ? substr($auth, 7) : ($_SERVER["HTTP_ALLPAY_TOKEN"] ?? ""); if (!hash_equals($token, $got)) { http_response_code(401); exit; } $tx = json_decode(file_get_contents("php://input"), true); // chống trùng theo $tx["transaction_id"], rồi ghi nhận $tx["code"], $tx["transferAmount"], $tx["virtualAccount"] http_response_code(200); echo "ok"; ``` ## Phản hồi và thử lại | Phản hồi của bạn | TinoPay hiểu là | | --- | --- | | HTTP 2xx (200–299) | thành công, không gửi lại | | mã khác (4xx, 5xx), không phản hồi hoặc hết thời gian chờ | thất bại, sẽ gửi lại | TinoPay chỉ xét mã HTTP, không xét body: trả `200 OK` là đủ, `{"success": true}` là thói quen tốt nhưng không bắt buộc. Xử lý đồng bộ mà chậm thì request có thể hết thời gian chờ và bị tính là thất bại. Lần gửi đầu không nhận được 2xx: TinoPay lên lịch gửi lại sau 5 phút, tác vụ gửi lại thử tối đa 3 lần. Vì vậy một giao dịch có thể tạo nhiều lần gọi tới webhook của bạn. ## Log và gửi lại Mỗi lần gửi được ghi log: payload gửi đi, câu trả lời của máy chủ bạn, mã HTTP (`status_code`), `success`, URL và phương thức, giao dịch liên quan. - Trên web TinoPay: menu Tích hợp → Lịch sử webhook (`/webhookslog`), bấm một dòng để xem chi tiết, nút Gọi lại để gửi lại. Ở trang chi tiết giao dịch, nút Gửi lại hook gửi lại tới mọi webhook, kênh thông báo và Google Sheets đang bật. - [Log webhook](/docs/api/tinopay-get-webhook-logs): lọc `status=failed` để xem lần lỗi. - [Gửi lại log webhook](/docs/api/tinopay-post-webhook-logs-log-resend): gửi lại đúng request đó tới đúng webhook đó. - [Bắn lại webhook cho giao dịch](/docs/api/tinopay-post-transactions-transaction-resend-webhook): gửi giao dịch tới mọi webhook đang bật của tài khoản ngân hàng. - [Lịch sử giao dịch](/docs/api/tinopay-get-transactions) với `webhook_status=failed` hoặc `none`: giao dịch chưa gửi được. - Merchant tạm ngưng: giao dịch vẫn được ghi nhận nhưng không gửi webhook; khi mở lại, đối chiếu bằng lịch sử giao dịch. - Xoá webhook thì xoá luôn toàn bộ log của nó. ## Danh sách kiểm tra - URL webhook chạy HTTPS. - Xác minh token ở mọi request. - Trả HTTP 2xx ngay khi nhận; việc nặng đưa vào hàng đợi. - Chống trùng bằng `transaction_id` hoặc `referenceCode`. - Kiểm `transferType` để chỉ xử lý đúng chiều tiền. - Đối chiếu định kỳ bằng [API lịch sử giao dịch](/docs/tinopay-api#lich-su-giao-dich) làm phương án dự phòng. --- # Đăng nhập từ CLI và ứng dụng không có backend Công cụ dòng lệnh (CLI), script và ứng dụng không có server riêng đăng nhập Tino theo kiểu `gh auth login`: CLI in ra một mã ngắn, khách mở `https://auth.tino.vn/oauth/device` trên trình duyệt bất kỳ (máy tính hay điện thoại), nhập mã và bấm Cho phép, CLI nhận token. Không cần redirect URI, không cần `client_secret`. Cập nhật: 2026-10-27. Mọi endpoint có trong tài liệu discovery `https://api.tino.vn/.well-known/oauth-authorization-server` (`registration_endpoint`, `device_authorization_endpoint`, `token_endpoint`). | Mục | Giá trị | | --- | --- | | Đăng ký ứng dụng (`registration_endpoint`) | `POST https://api.tino.vn/oauth/register` | | Xin mã thiết bị (`device_authorization_endpoint`) | `POST https://api.tino.vn/oauth/device_authorization` | | Trang khách nhập mã (`verification_uri`) | `https://auth.tino.vn/oauth/device` | | Hỏi token, làm mới token (`token_endpoint`) | `POST https://api.tino.vn/oauth/token` | | Thu hồi token (`revocation_endpoint`) | `POST https://api.tino.vn/oauth/revoke` | | Gọi API thay khách | `https://api.tino.vn/v1/` | | `grant_type` của mã thiết bị | `urn:ietf:params:oauth:grant-type:device_code` | | Mã khách nhập (`user_code`) | 8 chữ dạng `XXXX-XXXX`, hết hạn sau 600 giây | Ứng dụng có trình duyệt và nhận được redirect (web, mobile, MCP client) dùng luồng Authorization Code + PKCE ở trang [Đăng nhập bằng Tino](/docs/oauth); trang này cho phần còn lại. ## Luồng đăng nhập bằng mã thiết bị 1. CLI gọi `POST /oauth/device_authorization` → nhận `device_code` (giữ bí mật) và `user_code` (cho khách xem). 2. CLI in ra: "Mở https://auth.tino.vn/oauth/device và nhập mã LPMR-SKST" — hoặc mở sẵn `verification_uri_complete` (đã kèm mã). 3. Khách đăng nhập Tino (nếu chưa), nhập mã, xem tên ứng dụng và các quyền xin, bấm Cho phép hoặc Từ chối. 4. Trong lúc đó CLI hỏi `POST /oauth/token` mỗi `interval` giây với `device_code`, tới khi nhận token, bị từ chối hoặc mã hết hạn. 5. CLI gọi `https://api.tino.vn/v1/` với `Authorization: Bearer `. ## Đăng ký ứng dụng Có hai cách lấy `client_id`. **Tự đăng ký (RFC 7591).** Gọi một lần lúc cài đặt hoặc lần chạy đầu, lưu `client_id` lại: ```bash curl -X POST https://api.tino.vn/oauth/register \ -H "Content-Type: application/json" \ -d '{"client_name":"My CLI","grant_types":["urn:ietf:params:oauth:grant-type:device_code","refresh_token"],"scope":"offline_access profile:read services:read"}' ``` Câu trả lời (HTTP 201): ```json { "client_id": "…", "client_id_issued_at": 1793106000, "client_name": "My CLI", "grant_types": ["urn:ietf:params:oauth:grant-type:device_code", "refresh_token"], "token_endpoint_auth_method": "none", "scope": "offline_access profile:read services:read" } ``` | Trường | Quy tắc | | --- | --- | | `client_name` | tên hiện cho khách khi nhập mã; tối đa 100 ký tự | | `grant_types` | trong số `authorization_code`, `refresh_token`, `urn:ietf:params:oauth:grant-type:device_code` | | `redirect_uris` | bắt buộc khi có `authorization_code`: `https://`, `http://localhost` / `127.0.0.1` / `[::1]` (mọi cổng) hoặc scheme riêng của ứng dụng (`myapp://callback`); không có `#` | | `scope` | các quyền cách nhau dấu cách (bảng quyền ở [Đăng nhập bằng Tino](/docs/oauth)); bỏ trống = mọi quyền ứng dụng được xin | | `logo_uri` | không bắt buộc, `https://` | | `token_endpoint_auth_method` | chỉ `none`: ứng dụng tự đăng ký là client công khai, không có `client_secret` | Đăng ký không cấp quyền gì: khách vẫn phải tự nhập mã và bấm Cho phép. Mỗi địa chỉ IP đăng ký tối đa 10 lần mỗi giờ (`429 too_many_requests`). Lỗi metadata: `400 invalid_client_metadata` hoặc `400 invalid_redirect_uri`, câu tiếng Anh trong `error_description`. **Tino tạo ứng dụng.** Liên hệ Tino để tạo ứng dụng có bật "CLI (device code)"; dùng khi cần `client_secret` hoặc tên, logo cố định. ## Bước 1 — Xin mã thiết bị `POST https://api.tino.vn/oauth/device_authorization`, body `application/x-www-form-urlencoded`: | Tham số | Giá trị | | --- | --- | | `client_id` | client_id của bạn | | `scope` | các quyền cách nhau dấu cách; bỏ trống = các quyền của ứng dụng. Thêm `offline_access` để có refresh token | | `client_secret` | chỉ client confidential do Tino tạo | ```bash curl -X POST https://api.tino.vn/oauth/device_authorization \ -d client_id=YOUR_CLIENT_ID \ -d "scope=offline_access services:read" ``` Câu trả lời (HTTP 200): ```json { "device_code": "…", "user_code": "LPMR-SKST", "verification_uri": "https://auth.tino.vn/oauth/device", "verification_uri_complete": "https://auth.tino.vn/oauth/device?user_code=LPMR-SKST", "expires_in": 600, "interval": 5 } ``` | Lỗi | Nghĩa | | --- | --- | | `401 invalid_client` | `client_id` không có, bị tắt, hoặc sai `client_secret` | | `400 unauthorized_client` | ứng dụng chưa bật đăng nhập bằng mã thiết bị | | `400 invalid_scope` | quyền lạ hoặc ngoài quyền của ứng dụng | `device_code` là bí mật của CLI: không in ra, không ghi log. Chỉ `user_code` và địa chỉ trang là cho khách xem. ## Bước 2 — Khách nhập mã In `verification_uri` và `user_code` để khách gõ trên bất kỳ thiết bị nào; máy có trình duyệt thì mở sẵn `verification_uri_complete`. Trên trang của Tino, khách đăng nhập (nếu chưa), thấy tên ứng dụng, các quyền xin và thời gian mã còn hiệu lực, rồi bấm Cho phép hoặc Từ chối. Trang nhắc khách chỉ nhập mã vừa thấy trên máy của chính mình. ## Bước 3 — Hỏi token Mỗi `interval` giây gọi `POST https://api.tino.vn/oauth/token`, body `application/x-www-form-urlencoded`: | Tham số | Giá trị | | --- | --- | | `grant_type` | `urn:ietf:params:oauth:grant-type:device_code` | | `device_code` | `device_code` ở bước 1 | | `client_id` | client_id của bạn | | `client_secret` | chỉ client confidential | Trong lúc chờ, Tino trả HTTP 400 với `error`: | `error` | Việc CLI làm | | --- | --- | | `authorization_pending` | khách chưa trả lời: chờ `interval` giây rồi hỏi tiếp | | `slow_down` | hỏi nhanh quá: tăng khoảng chờ thêm 5 giây, giữ mức mới cho các lần sau | | `access_denied` | khách bấm Từ chối: dừng | | `expired_token` | quá 10 phút: xin mã mới (bước 1) | | `invalid_grant` | `device_code` sai hoặc đã dùng: dừng | Khách bấm Cho phép, lần hỏi kế tiếp nhận HTTP 200 (mỗi `device_code` chỉ đổi được một lần): ```json { "access_token": "tinoat_…", "token_type": "Bearer", "expires_in": 86400, "scope": "offline_access services:read", "refresh_token": "tinort_…" } ``` `refresh_token` chỉ có khi `scope` có `offline_access`. ## Bước 4 — Gọi API ```bash curl https://api.tino.vn/v1/service -H "Authorization: Bearer $ACCESS_TOKEN" ``` Quyền trong `scope` quyết định route nào gọi được: bảng quyền và route ở [Đăng nhập bằng Tino](/docs/oauth), từng route ở [API Reference](/docs/reference). ## Làm mới và thu hồi - Làm mới khi `access_token` hết hạn (`expires_in` 86400 giây, 24 giờ): `POST /oauth/token` với `grant_type=refresh_token`, `client_id`, `refresh_token`. Mỗi lần làm mới trả refresh token mới và vô hiệu hoá cái cũ; lưu ngay bản mới. Dùng lại refresh token cũ thì Tino thu hồi toàn bộ quyền của ứng dụng, khách phải nhập mã lại. - Đăng xuất: `POST /oauth/revoke` với `token=`, `client_id`. Khách cũng tự thu hồi được ở trang Ứng dụng được cấp quyền (`https://auth.tino.vn/me/apps`). Chi tiết tham số: [Đăng nhập bằng Tino](/docs/oauth). ## Lưu token an toàn - Lưu token trong file riêng của người dùng, ví dụ `~/.config//token.json`, quyền `600` (chỉ chủ file đọc ghi); hoặc keychain của hệ điều hành. - Không in token, `device_code` ra màn hình hay log; không đưa token vào tham số dòng lệnh (lộ qua danh sách tiến trình). - Chỉ xin các quyền thật sự cần; thêm `offline_access` khi CLI cần chạy lâu mà không bắt khách nhập mã lại. ## Ví dụ bash Cần `curl` và `jq`. ```bash #!/usr/bin/env bash set -euo pipefail CLIENT_ID="${TINO_CLIENT_ID:?đặt TINO_CLIENT_ID}" API=https://api.tino.vn start=$(curl -s -X POST "$API/oauth/device_authorization" -d client_id="$CLIENT_ID" -d "scope=offline_access services:read") device_code=$(jq -r .device_code <<<"$start") interval=$(jq -r .interval <<<"$start") echo "Mở $(jq -r .verification_uri <<<"$start") và nhập mã $(jq -r .user_code <<<"$start")" while true; do sleep "$interval" reply=$(curl -s -X POST "$API/oauth/token" \ -d grant_type=urn:ietf:params:oauth:grant-type:device_code \ -d device_code="$device_code" -d client_id="$CLIENT_ID") case "$(jq -r '.error // empty' <<<"$reply")" in "") break ;; authorization_pending) ;; slow_down) interval=$((interval + 5)) ;; *) echo "Đăng nhập không thành công: $(jq -r .error <<<"$reply")" >&2; exit 1 ;; esac done mkdir -p ~/.config/my-cli ( umask 077; printf '%s' "$reply" > ~/.config/my-cli/token.json ) echo "Đã đăng nhập." ``` ## Ví dụ Node.js Node.js 18+ (có sẵn `fetch`), không cần thư viện. ```javascript import { mkdir, writeFile } from "node:fs/promises"; import { homedir } from "node:os"; import { join } from "node:path"; const API = "https://api.tino.vn"; const clientId = process.env.TINO_CLIENT_ID; const form = (body) => ({ method: "POST", body: new URLSearchParams(body) }); const start = await (await fetch(`${API}/oauth/device_authorization`, form({ client_id: clientId, scope: "offline_access services:read" }))).json(); console.log(`Mở ${start.verification_uri} và nhập mã ${start.user_code}`); let interval = start.interval; let token; while (!token) { await new Promise((done) => setTimeout(done, interval * 1000)); const reply = await (await fetch(`${API}/oauth/token`, form({ grant_type: "urn:ietf:params:oauth:grant-type:device_code", device_code: start.device_code, client_id: clientId, }))).json(); if (!reply.error) token = reply; else if (reply.error === "slow_down") interval += 5; else if (reply.error !== "authorization_pending") throw new Error(`Đăng nhập không thành công: ${reply.error}`); } const dir = join(homedir(), ".config", "my-cli"); await mkdir(dir, { recursive: true, mode: 0o700 }); await writeFile(join(dir, "token.json"), JSON.stringify(token), { mode: 0o600 }); console.log("Đã đăng nhập."); ``` ## Ví dụ Python Python 3, chỉ dùng thư viện chuẩn. ```python import json, os, time, urllib.error, urllib.parse, urllib.request API = "https://api.tino.vn" CLIENT_ID = os.environ["TINO_CLIENT_ID"] def post(path, body): request = urllib.request.Request(API + path, data=urllib.parse.urlencode(body).encode()) try: with urllib.request.urlopen(request) as response: return json.load(response) except urllib.error.HTTPError as error: # 400 authorization_pending, slow_down… return json.load(error) start = post("/oauth/device_authorization", {"client_id": CLIENT_ID, "scope": "offline_access services:read"}) print(f"Mở {start['verification_uri']} và nhập mã {start['user_code']}") interval = start["interval"] while True: time.sleep(interval) reply = post("/oauth/token", {"grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": start["device_code"], "client_id": CLIENT_ID}) error = reply.get("error") if not error: break if error == "slow_down": interval += 5 elif error != "authorization_pending": raise SystemExit(f"Đăng nhập không thành công: {error}") path = os.path.expanduser("~/.config/my-cli/token.json") os.makedirs(os.path.dirname(path), mode=0o700, exist_ok=True) with open(os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600), "w") as file: json.dump(reply, file) print("Đã đăng nhập.") ``` ## Tham khảo - RFC 8628 — OAuth 2.0 Device Authorization Grant - RFC 7591 — OAuth 2.0 Dynamic Client Registration - [Đăng nhập bằng Tino (OAuth 2.0, OpenID Connect)](/docs/oauth) - [Token API cá nhân](/docs/personal-tokens): khách tự tạo token cho script của mình, không cần đăng ký ứng dụng --- # SDK & Ví dụ SDK chính thức của Tino cho Python, Node.js và PHP, mã nguồn mở ở [tinovn/tino-sdk](https://github.com/tinovn/tino-sdk) (giấy phép MIT). Mỗi route có một hàm `client..()`; SDK mã hoá query kiểu `filter[key]=value`, đọc lỗi trong body (kể cả HTTP 200 kèm `error`) và ném lỗi có kiểu. Cập nhật: 2026-10-27. ## Cài đặt | Ngôn ngữ | Lệnh cài | Phiên bản đang phát hành | Yêu cầu | | --- | --- | --- | --- | | Python | `pip install tino-userapi` | 1.2.0 (PyPI) | Python 3.8+, không phụ thuộc gói khác | | Node.js | `npm install @tinovn/tino-sdk` | 1.1.0 (npm) | Node.js 18+, ESM, có định nghĩa TypeScript, không phụ thuộc gói khác | | PHP | `composer require tinovn/tino-sdk` | 1.1.0 (Packagist) | PHP 7.4+, PSR-4, không phụ thuộc gói khác | ## Khởi tạo client Trỏ SDK vào gateway `https://api.tino.vn/v1` và truyền token: [token API cá nhân](/docs/personal-tokens) (`tinopat_`) hoặc access token của [Đăng nhập bằng Tino](/docs/oauth) (`tinoat_`). Token đọc từ biến môi trường `TINO_TOKEN`, không ghi vào mã nguồn. ```python import os from tino_userapi import TinoClient client = TinoClient(base_url="https://api.tino.vn/v1", token=os.environ["TINO_TOKEN"]) print(client.account.get_details()) ``` ```javascript import { TinoClient } from "@tinovn/tino-sdk"; const client = new TinoClient({ baseUrl: "https://api.tino.vn/v1", token: process.env.TINO_TOKEN }); console.log(await client.account.getDetails()); ``` ```php "https://api.tino.vn/v1", "token" => getenv("TINO_TOKEN")]); print_r($client->account->getDetails()); ``` Không truyền refresh token OAuth cho SDK: SDK tự làm mới theo cách đăng nhập riêng của nó, không qua `/oauth/token`. Access token OAuth hết hạn (mặc định 24 giờ) thì ứng dụng [làm mới token](/docs/oauth#lam-moi-va-thu-hoi-token) rồi tạo client với token mới. ## Gọi một route Mỗi trang route ở [API Reference](/docs/reference) có đoạn gọi SDK của route đó, ở cột Ví dụ yêu cầu. Tham số đường dẫn là đối số theo thứ tự; body là đối số tên (Python), đối tượng (Node.js) hoặc mảng (PHP). Ví dụ thêm bản ghi DNS (quyền `dns:write`): ```python client.dns.create_record("100003", "500001", name="www", type="A", content="203.0.113.10", ttl=3600, priority=0) ``` ```javascript await client.dns.createRecord("100003", "500001", { name: "www", type: "A", content: "203.0.113.10", ttl: 3600, priority: 0 }); ``` ```php $client->dns->createRecord("100003", "500001", ["name" => "www", "type" => "A", "content" => "203.0.113.10", "ttl" => 3600, "priority" => 0]); ``` ## Route chưa có hàm riêng Một số route của gateway chưa có hàm trong SDK (trang route ghi rõ). Gọi bằng `request` với đường dẫn không có tiền tố `/v1` (base URL đã có): ```python records = client.request("GET", "/domain/200001/dns") ``` ```javascript const records = await client.request("GET", "/domain/200001/dns"); ``` ```php $records = $client->request("GET", "/domain/200001/dns"); ``` Body truyền qua `body=` (Python), `{ body: … }` (Node.js) hoặc `["body" => …]` (PHP); query qua `query`. ## Lỗi | Tình huống | Python, Node.js | PHP | | --- | --- | --- | | HTTP 401 `invalid_token` (token sai, hết hạn, đã thu hồi) | `TinoAuthError` | `TinoAuthException` | | HTTP 403 `insufficient_scope`, `ip_not_allowed` | `TinoApiError` | `TinoApiException` | | Không tìm thấy | `TinoNotFoundError` | `TinoNotFoundException` | | Dữ liệu gửi lên sai | `TinoValidationError` | `TinoValidationException` | | Bị giới hạn tần suất | `TinoRateLimitError` | `TinoRateLimitException` | | Lỗi mạng, hết thời gian chờ | `TinoTransportError` | `TinoTransportException` | Mọi lỗi kế thừa `TinoError` (`TinoException` ở PHP); lỗi từ API mang mã lỗi gốc (ví dụ `insufficient_scope`). ## Ví dụ: dịch vụ sắp hết hạn Liệt kê dịch vụ đang hoạt động hết hạn trong 30 ngày tới (quyền `services:read`): ```python import os from datetime import date, timedelta from tino_userapi import TinoClient client = TinoClient(base_url="https://api.tino.vn/v1", token=os.environ["TINO_TOKEN"]) soon = (date.today() + timedelta(days=30)).isoformat() for service in client.services.list()["services"]: if service["status"] == "Active" and service["expires"] <= soon: print(service["id"], service["domain"], service["name"], service["expires"]) ``` ## Ví dụ: hoá đơn chưa thanh toán In các hoá đơn đến hạn (quyền `billing:read`): ```javascript import { TinoClient } from "@tinovn/tino-sdk"; const client = new TinoClient({ baseUrl: "https://api.tino.vn/v1", token: process.env.TINO_TOKEN }); const { invoices_due: due } = await client.billing.listInvoicesDue(); for (const invoice of due) console.log(invoice.number, invoice.total, invoice.currency, invoice.duedate); ``` ## Ví dụ: cập nhật bản ghi A khi IP đổi Trỏ `home.example.com` về IP mới, kiểu DNS động (quyền `dns:read`, `dns:write`). Vùng DNS lấy theo tên miền; `zone_id` là `domain_id` của vùng. Khi đọc, tên bản ghi đầy đủ (`home.example.com`); khi thêm, sửa, gửi tên tương đối (`home`): ```python import os from tino_userapi import TinoClient client = TinoClient(base_url="https://api.tino.vn/v1", token=os.environ["TINO_TOKEN"]) new_ip = "203.0.113.25" zone = next(z for z in client.dns.list_zones_all()["zones"] if z["name"] == "example.com") records = client.dns.get_zone(zone["service_id"], zone["domain_id"])["records"].values() record = next(r for r in records if r["type"] == "A" and r["name"] == "home.example.com") if record["content"] != new_ip: client.dns.update_record(zone["service_id"], zone["domain_id"], record["id"], name="home", type="A", content=new_ip, ttl=record["ttl"], priority=record["priority"]) ``` Các ví dụ đọc dữ liệu theo dạng mẫu response trên trang route; chạy thử với token chỉ đủ quyền cần dùng, xem [Môi trường thử nghiệm](/docs/sandbox). --- # Thông báo Telegram, Zalo, Lark Ngoài [webhook](/docs/tinopay-webhook), TinoPay gửi thông báo từng giao dịch vào Telegram, Zalo hoặc Lark. Mỗi ứng dụng thông báo gắn một tài khoản ngân hàng và lọc theo tài khoản ảo như webhook. Các route ở nhóm Thông báo của [API Reference](/docs/reference#tinopay); cách gọi, xác thực, mã lỗi ở [Bắt đầu với TinoPay](/docs/tinopay-start). Cập nhật: 2026-10-25. Nguồn: module TinoPay của Tino và tài liệu TinoPay API v1. ## Loại ứng dụng | `type` | Bot | `endpoint` (nơi nhận) | | --- | --- | --- | | `telegram` | mặc định bot chung **@allpay_telebot**; gửi `bot_token` để dùng bot riêng | bot chung: ID nhóm bắt đầu bằng `-` (thêm @allpay_telebot vào nhóm); bot riêng: ID nhóm (`-…`) hoặc chat cá nhân (số dương) | | `zalo` | bắt buộc bot riêng (`bot_token` từ Zalo Bot Creator) | `chat_id` Zalo của chat cá nhân hoặc nhóm (nhóm bắt đầu bằng `zgr-`) | | `lark` | URL webhook bot Lark, không có `bot_token` | `https://open.larksuite.com/open-apis/bot/v2/hook/…` (hoặc `open.feishu.cn`) | `bot_token` không bao giờ được trả về: danh sách chỉ có `bot_token_masked`. Khi làm giao diện, để ô token là ô mật khẩu và không điền lại khi sửa. ## Thêm ứng dụng (bot riêng) 1. [Kiểm token bot](/docs/api/tinopay-post-notification-apps-bot-info): `{type, bot_token}` → `{valid, bot_name, error}`. Hiện tên bot; `valid` là `false` thì hiện `error`. 2. [Tìm nơi nhận](/docs/api/tinopay-post-notification-apps-find-chats): `{type, bot_token}` → `{chats: [{id, title, type}], error}`; người dùng chọn một nơi nhận, `id` thành `endpoint`. 3. [Gửi tin thử](/docs/api/tinopay-post-notification-apps-test): `{type, endpoint, bot_token}` gửi một tin nhắn thật → `{connected, chat_title}`. Chỉ cho lưu khi `connected` là `true`; Telegram có `chat_title` để điền sẵn tên. 4. [Tạo ứng dụng](/docs/api/tinopay-post-notification-apps): `type`, `name` (tối đa 250 ký tự), `endpoint`, `bot_token`, `bank_account_id`, `virtual_accounts` (rỗng là mọi tài khoản ảo), `status` (`active` mặc định, `inactive`) → 201. `type` không đổi được sau khi tạo. Bước 2 theo từng loại: - Telegram trả ngay nhóm, người đã nhắn bot trong 24 giờ. `error` khác `null` (bot đang gắn webhook của hệ thống khác): cho nhập ID tay. - Zalo không lưu tin cũ: request chờ tới khoảng 20 giây và chỉ bắt tin nhắn gửi bot trong lúc chờ (nhóm: nhắc tên bot). Báo người dùng "hãy nhắn bot ngay", đặt timeout HTTP ít nhất 30 giây. Hết giờ chưa có tin thì `chats` rỗng: cho thử lại hoặc nhập tay. Bot chung Telegram: bỏ bước 1, 2; nhập ID nhóm, bước 3 không gửi `bot_token`. Lark: chỉ bước 3, 4 với `endpoint` là URL webhook. Bước 2 và 3 không tự thử lại khi lỗi mạng (thử lại sẽ chờ lâu gấp nhiều lần hoặc gửi tin thử hai lần): để người dùng bấm lại. ## Sửa ứng dụng - Bước 1–3 khi sửa gửi `app_id` thay `bot_token` để dùng token đang lưu; `app_id` phải là ứng dụng của merchant này, không thì 404 `RESOURCE_NOT_FOUND`. - [Sửa ứng dụng](/docs/api/tinopay-patch-notification-apps-app): chỉ gửi trường cần đổi, không gửi `type`. | `bot_token` khi sửa | Kết quả | | --- | --- | | không gửi | giữ token cũ | | chuỗi mới | đổi sang token mới | | `null` | Telegram về bot chung (`endpoint` phải là ID nhóm `-…`); Zalo không bỏ được token | Đổi sang `bank_account_id` không thuộc merchant: 404 `BANK_ACCOUNT_NOT_FOUND`. ## Theo dõi lỗi gửi [Danh sách ứng dụng](/docs/api/tinopay-get-notification-apps) có `last_error`, `last_error_at`: lỗi của lần gửi gần nhất (token bị thu hồi, bot bị đưa khỏi nhóm…). Hiện cảnh báo "Lỗi kết nối" kèm `last_error`; lần gửi sau thành công thì tự về `null`. Merchant tạm ngưng thì ngừng gửi thông báo, giống webhook. --- # Changelog Thay đổi của API, máy chủ MCP, SDK và tài liệu dành cho developer, mới nhất trước. ## 2026-10-28 - **Quyền:** `domains:registrant` (mới, chỉ token cá nhân) cho bốn route [hồ sơ chủ thể tên miền](/docs/domain-registrant), tách khỏi `domains:owner`; `domains:write` đổi nhãn "Đăng ký, gia hạn và quản lý tên miền"; `orders:write` (mới) cho [báo giá](/docs/api/post-quote), [giỏ hàng](/docs/api/post-carts) và [đặt đơn](/docs/api/post-order) — đặt đơn trừ số dư cần thêm `billing:write`. ## 2026-10-27 - **Identity & SSO:** access token và ID token OAuth có hạn mặc định 86400 giây (24 giờ), không phải 3600: sửa ở [Đăng nhập bằng Tino](/docs/oauth), [Đăng nhập từ CLI](/docs/cli-login), [MCP](/docs/mcp), [SDK](/docs/sdk). Vẫn đọc `expires_in` của mỗi câu trả lời thay vì ghi cứng. - **TinoPay, TinoPage Builder, TinoWAF:** gateway `/v1` mở các route của ba dịch vụ cho token ứng dụng OAuth và token API cá nhân, quyền mới `tinopay:read`, `tinopay:write`, `tinopay:owner` (chỉ token cá nhân), `builder:read`, `builder:write`, `waf:read`, `waf:write`: bảng ở [Đăng nhập bằng Tino](/docs/oauth), [Bắt đầu với TinoPay](/docs/tinopay-start), [Bắt đầu với TinoPage Builder](/docs/builder-start). - **Máy chủ MCP:** trang [Kết nối Claude, ChatGPT với Tino (MCP)](/docs/mcp): ứng dụng MCP khác đăng nhập OAuth bằng cách tự đăng ký client (`POST https://api.tino.vn/oauth/register`, RFC 7591); token API cá nhân là phương án thay thế. Claude Code nhận diện bằng Client ID Metadata Document, mặc định xin đủ các quyền máy chủ MCP liệt kê, gồm cả quyền ghi. - **Identity & SSO:** trang mới [Đăng nhập từ CLI và ứng dụng không có backend](/docs/cli-login): ứng dụng tự đăng ký (`POST https://api.tino.vn/oauth/register`, RFC 7591), đăng nhập bằng mã thiết bị (RFC 8628: `POST /oauth/device_authorization`, khách nhập mã ở `https://auth.tino.vn/oauth/device`, CLI hỏi `POST /oauth/token`), ví dụ bash, Node.js, Python. Trang [Đăng nhập bằng Tino](/docs/oauth) thêm hai endpoint mới và grant `urn:ietf:params:oauth:grant-type:device_code`. - **Domains:** trang mới [Hồ sơ chủ thể tên miền](/docs/domain-registrant) và 4 route: [tên miền chờ hoàn tất hồ sơ](/docs/api/get-domains-pending), [xem](/docs/api/get-domains-id-registrant) và [lưu chủ thể](/docs/api/put-domains-id-registrant) của tên miền đang chờ, [chủ thể đã dùng](/docs/api/get-registrants); cả bốn cần `domains:owner` (chỉ token API cá nhân), số giấy tờ trong `reason` được che. Tra whois gọi được cả qua `/v1` bằng token: [`GET /v1/whois/{domain}`](/docs/api/get-v1-whois-domain). - **TinoWAF, TinoPay, MCP:** mục API [TinoWAF](/docs/waf): 19 route `/v1/service/{id}/waf/…` (website, mức bảo vệ, chống tấn công khẩn cấp, tên miền, máy chủ gốc, nhật ký sự kiện, chặn hoặc cho phép IP), quyền `waf:read`, `waf:write`. TinoPay thêm 9 route: [cấu trúc mã thanh toán](/docs/api/tinopay-get-pay-codes), [tích hợp Sapo](/docs/api/tinopay-get-sapo-integrations), [nhật ký đối soát Sapo](/docs/api/tinopay-get-sapo-order-logs). Trang [MCP](/docs/mcp) thêm tool của 6 quyền TinoPay, TinoPage Builder, TinoWAF. ## 2026-10-26 - **Tên miền:** trang [Tra whois tên miền](/docs/api/get-whois-domain) (`GET https://api.tino.vn/whois/`): route công khai, không cần token; cách đọc `available`, `error`, `raw` khi bị giới hạn tần suất. - **TinoPage Builder:** mục mới: [Bắt đầu với TinoPage Builder](/docs/builder-start) và trang cho 14 route của API dịch vụ `https://api.tino.vn/service//builder/…` (tổng quan tài khoản và hạn mức, website, tạo website bằng AI, đăng, tạm ngưng, xoá, tên miền riêng, liên hệ và đơn hàng, vé đăng nhập một lần), gọi bằng token đăng nhập của chủ dịch vụ. ## 2026-10-24 - **Tino Uptime:** mục mới: [Bắt đầu với Tino Uptime](/docs/uptime-start) và trang cho 20 route của API dịch vụ `https://api.tino.vn/service//uptime/…` (gói, mức dùng, monitor, uptime, kết quả kiểm, sự cố, kênh cảnh báo), gọi bằng token đăng nhập của chủ dịch vụ. ## 2026-10-22 - **TinoPay:** route merchant bỏ tiền tố `/v2/services`, nay là `https://api.tino.vn/service//tinopay/…`; đường cũ trả 404 `invalid method`. Thêm 11 route: [thông báo Telegram, Zalo, Lark](/docs/tinopay-notifications) và [API token](/docs/tinopay-start#api-token). Nhận diện dịch vụ TinoPay theo `product_type` (`tinopay`) thay cho tên dịch vụ; đặt timeout ít nhất 100 giây ([Bắt đầu với TinoPay](/docs/tinopay-start)). ## 2026-10-21 - **Tài liệu:** developers.tino.vn có trang cho từng route của gateway `/v1` (tham số, ví dụ cURL, JavaScript, PHP, SDK, mẫu response), [API Reference](/docs/reference) theo sản phẩm, [OpenAPI 3.1](/openapi.json), `llms.txt` và bản Markdown của mọi trang. - **Tài liệu:** thêm trang [Kết nối Claude, ChatGPT với Tino (MCP)](/docs/mcp), [Token API cá nhân](/docs/personal-tokens), [SDK & Ví dụ](/docs/sdk), [Môi trường thử nghiệm](/docs/sandbox). - **Tài liệu:** mục TinoPay: [Bắt đầu với TinoPay](/docs/tinopay-start), [Nhận webhook TinoPay](/docs/tinopay-webhook) và trang cho từng route của API merchant TinoPay. ## 2026-10-20 - **Đăng nhập bằng Tino:** OAuth 2.0 Authorization Code + PKCE (S256) và OpenID Connect; issuer `https://api.tino.vn`, trang đăng nhập và đồng ý `https://auth.tino.vn/oauth/consent`. Xem [Đăng nhập bằng Tino](/docs/oauth). - **Gateway `/v1`:** gọi API thay khách ở `https://api.tino.vn/v1/`; mỗi route cần một quyền, ngoài quyền trả 403 `insufficient_scope`. Xem [Gọi API Tino](/docs/api). - **Token API cá nhân** (`tinopat_`): khách tạo ở `https://auth.tino.vn/me/security`, chọn quyền, hạn dùng, giới hạn IP; quyền `domains:owner` chỉ token cá nhân có và bắt buộc giới hạn IP. - **Máy chủ MCP** `https://api.tino.vn/mcp`: Claude, Claude Code, ChatGPT đăng nhập OAuth; ứng dụng MCP khác dùng token cá nhân. Không có tool huỷ dịch vụ. ## SDK 1.2.0 (2026-10-13) - Nhóm `backorder`: đấu giá tên miền .vn. Bản 1.2.0 có trên PyPI; npm và Packagist đang ở 1.1.0. ## SDK 1.1.0 (2026-08-04) - Xác minh số điện thoại của tài khoản; mã gửi qua Zalo, số chưa có Zalo thì qua SMS. ## SDK 1.0.0 (2026-08-02) - SDK Python, Node.js, PHP và tài liệu hợp đồng cho từng thao tác: [tinovn/tino-sdk](https://github.com/tinovn/tino-sdk). --- # 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](/docs/tinopay-start#goi-api-merchant) (`https://api.tino.vn/service//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](https://pay.tino.vn/docs). ## 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](/docs/tinopay-webhook) để nhận giao dịch tức thời và dùng [lịch sử giao dịch](#lich-su-giao-dich) để đố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 `, trừ danh sách ngân hàng và ảnh QR | ```bash 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: ```http Authorization: Bearer ``` ### 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](/docs/api/tinopay-post-api-tokens), xem mục [API token](/docs/tinopay-start#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_id` của người khác) thì API không trả dữ liệu. ### Ví dụ gọi JavaScript: ```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): ```php $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 ```http 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_date` giả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ả `from` lẫn `to`: lấy trong ngày hôm nay. - Chỉ truyền một trong hai: lấy trọn đúng ngày đó. - `from` phải nhỏ hơn hoặc bằng `to`, cách nhau tối đa 90 ngày. ```bash 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" ``` ```javascript 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`: ```json { "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 ```http GET https://pay.tino.vn/api/banks ``` Ngâ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](#tao-ma-vietqr). Không cần xác thực. Trả một mảng JSON, không bọc trong `data`. ```bash curl "https://pay.tino.vn/api/banks" -H "Accept: application/json" ``` ```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 ```http GET https://pay.tino.vn/img-qr ``` Sinh 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ẻ ``, 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ó header `Access-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](#danh-sach-ngan-hang) | | `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 | ```html Quét QR để thanh toán ``` Đủ tham số: ```text 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=1 ``` Chỉ mã QR, không khung: ```text https://pay.tino.vn/img-qr?bank_code=BIDV&account_no=96240000001&amount=150000&memo=DH12345&template=only-qr ``` Thiế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](/docs/tinopay-webhook) nhận giao dịch kèm nội dung này (và `code` nếu khớp [mã thanh toán](/docs/api/tinopay-patch-merchant)), 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. --- # Tích hợp không cần code TinoPay có sẵn bốn tích hợp cấu hình trên web TinoPay (menu Tích hợp), không cần tự dựng endpoint: Google Sheets ghi giao dịch vào bảng tính; plugin WordPress / WooCommerce, module HostBill và Sapo hiện mã VietQR và tự xác nhận đơn hàng, hoá đơn khi khách chuyển khoản. Cần tích hợp sâu hơn vào hệ thống của bạn: xem [webhook](/docs/tinopay-webhook) và [API công khai](/docs/tinopay-api). Cập nhật: 2026-10-25. Nguồn: [tài liệu TinoPay](https://pay.tino.vn/docs/google-sheets), mục Tích hợp không cần code. Ba tích hợp bán hàng khớp giao dịch theo mã thanh toán trong nội dung chuyển khoản: tiền tố khai ở web TinoPay (Cài đặt → Cấu trúc mã thanh toán) phải trùng tiền tố cấu hình ở plugin, module hay cửa hàng. ## Google Sheets TinoPay tự ghi mọi giao dịch khớp điều kiện vào một bảng tính Google của bạn ngay khi ngân hàng báo biến động số dư; hợp với kế toán, chủ shop muốn theo dõi dòng tiền bằng bảng tính. TinoPay gom giao dịch khoảng 10 giây rồi ghi một lượt nhiều dòng để không chạm hạn mức của Google Sheets API, nên dòng mới thường xuất hiện sau vài giây chứ không tức thì. Cần một tài khoản Google (Gmail hoặc Google Workspace) và ít nhất một tài khoản ngân hàng đã kết nối với TinoPay. ### Thiết lập Google Sheets Menu Tích hợp → Google Sheets → Thêm tích hợp, bốn bước: 1. Tài khoản Google: lần đầu bấm Đăng nhập bằng Google và chọn tài khoản chứa bảng tính; đã liên kết thì chọn trong danh sách hoặc bấm Liên kết tài khoản Google khác. Màn cấp quyền của Google có ô quyền truy cập Google Drive để trống mặc định: phải tích vào, không thì TinoPay không tạo hay ghi được bảng tính nào. 2. Bảng tính: Tạo mới bảng tính (TinoPay tạo sẵn đúng định dạng cột; đặt tên, chọn thư mục trong My Drive) hoặc Chọn bảng tính có sẵn (TinoPay tự thêm hàng tiêu đề nếu trang tính còn trống). Chọn trang tính (sheet) nhận dữ liệu và tuỳ chọn Tự động xóa giao dịch cũ sau: Không xóa (giữ toàn bộ, bảng tính lớn dần), 60 phút, 4 tiếng, 8 tiếng hoặc 1 ngày (xoá dòng cũ hơn mốc này, dọn mỗi 10 phút). 3. Phạm vi: Tất cả ngân hàng (mọi tài khoản, kể cả tài khoản thêm sau) hoặc Tùy chỉnh ngân hàng (chỉ tài khoản bạn chọn, lọc tiếp theo tài khoản ảo; không chọn tài khoản ảo nào là nhận toàn bộ giao dịch của tài khoản đó). Loại giao dịch: Tất cả, Tiền vào, Tiền ra. Ẩn số dư giao dịch: cột Lũy kế để trống, dùng khi chia sẻ bảng tính cho người khác. 4. Xác nhận: đặt tên gợi nhớ, kiểm bảng tóm tắt rồi bấm Lưu tích hợp. Từ đó mọi giao dịch khớp điều kiện được ghi vào bảng tính. Dòng đã xoá khỏi bảng tính vẫn còn trong TinoPay: tra ở menu Giao dịch → Lịch sử giao dịch hoặc qua [API lịch sử giao dịch](/docs/tinopay-api#lich-su-giao-dich). ### Cột của bảng tính TinoPay ghi đúng 10 cột theo thứ tự: | Cột | Tiêu đề | Nội dung | | --- | --- | --- | | A | Ngân hàng | tên đầy đủ của ngân hàng | | B | Ngày giao dịch | dạng `YYYY-MM-DD HH:MM:SS` | | C | Số tài khoản | số tài khoản ngân hàng nhận, chi tiền | | D | Tài khoản phụ | số tài khoản ảo, trống nếu giao dịch không qua tài khoản ảo | | E | Code TT | mã thanh toán trích từ nội dung chuyển khoản theo cấu trúc mã thanh toán; không khớp mã nào thì trống | | F | Nội dung thanh toán | nội dung chuyển khoản | | G | Loại | `Tiền vào` hoặc `Tiền ra` | | H | Số tiền | số tiền giao dịch | | I | Mã tham chiếu | mã tham chiếu của ngân hàng | | J | Lũy kế | số dư sau giao dịch, trống nếu bật Ẩn số dư | ### Quyền và lưu ý - TinoPay chỉ xin một quyền trên Google Drive: `drive.file`, chỉ những file TinoPay tạo hoặc bạn chọn qua hộp thoại chọn file; TinoPay không đọc được file khác trong Drive. Thu hồi bất kỳ lúc nào tại [myaccount.google.com/permissions](https://myaccount.google.com/permissions) hoặc bằng cách xoá tích hợp. - Không đổi tên, chèn hay xoá 10 cột mặc định: TinoPay ghi theo thứ tự cột, đổi cấu trúc thì dữ liệu ghi sai chỗ. Cột riêng thêm ở bên phải cột J. Không xoá hàng tiêu đề ở dòng 1. - Thu hồi quyền phía Google hoặc xoá bảng tính: tích hợp tự chuyển sang Tạm dừng kèm thông báo lỗi; liên kết lại tài khoản Google để tiếp tục. - Tạo được nhiều tích hợp trỏ tới nhiều bảng tính, ví dụ mỗi chi nhánh một bảng. - Cột Đẩy gần nhất ở trang danh sách là lần ghi thành công gần nhất; có lỗi thì biểu tượng cảnh báo cạnh tên tích hợp hiện chi tiết khi rê chuột. | Hiện tượng | Nguyên nhân thường gặp | | --- | --- | | bảng tính không có dòng nào | chưa có giao dịch khớp điều kiện lọc ở bước 3, hoặc tích hợp đang Tạm dừng | | tích hợp tự chuyển sang Tạm dừng | quyền Google đã bị thu hồi, hoặc bảng tính bị xoá, đổi chủ sở hữu | | không tạo được bảng tính | ở bước cấp quyền chưa tích ô quyền Google Drive | | dữ liệu ghi lệch cột | cấu trúc 10 cột mặc định đã bị sửa | ## WordPress / WooCommerce Plugin TinoPay Gateway thêm phương thức chuyển khoản bằng mã VietQR vào WooCommerce và tự xác nhận đơn hàng khi khách chuyển khoản. Plugin dùng [webhook](/docs/tinopay-webhook) ở phía sau nhưng tự cấu hình, bạn không cần dựng endpoint. 1. Khách đặt hàng; trang cảm ơn hiện mã VietQR, nội dung chuyển khoản `DH`. 2. Khách quét và chuyển khoản; TinoPay ghi nhận giao dịch, trích mã `DH`. 3. Webhook gửi về website; plugin khớp đơn và đổi trạng thái. - Chuyển đủ tiền: đơn chuyển sang trạng thái bạn chọn (mặc định Đang xử lý) và trừ tồn kho. - Chuyển thiếu hoặc thừa: đơn giữ nguyên trạng thái, plugin ghi chú số tiền thiếu, thừa để bạn xử lý. - Trang thanh toán của khách tự hiện "Bạn đã thanh toán thành công" khi đơn được xác nhận. Yêu cầu: WordPress 5.6+, PHP 7.2+, đã cài WooCommerce; website chạy HTTPS (bắt buộc để nhận webhook và kết nối an toàn); tài khoản TinoPay (đăng nhập bằng tài khoản Tino) và ít nhất một tài khoản ngân hàng đã kết nối. Hiện tự xác nhận hỗ trợ BIDV và cần có tài khoản ảo. ### Cài plugin 1. [Tải plugin TinoPay Gateway (.zip)](https://pay.tino.vn/downloads/tinopay-gateway.zip), hoặc trên web TinoPay: Tích hợp → WordPress → Tải plugin (.zip). 2. Trong WordPress: Plugin → Cài mới → Tải plugin lên, chọn file zip, bấm Cài đặt rồi Kích hoạt. 3. WooCommerce → Cài đặt → Thanh toán → TinoPay, bấm Kết nối TinoPay: trình duyệt chuyển sang TinoPay; đăng nhập bằng tài khoản Tino, kiểm tên website rồi bấm Cho phép kết nối. 4. Chọn tài khoản ngân hàng (BIDV: chọn thêm tài khoản ảo, mã QR dùng số tài khoản ảo này) rồi bấm Hoàn tất thiết lập. Plugin tự tạo webhook trên TinoPay (xem ở Tích hợp → Webhooks) và đồng bộ cấu trúc mã thanh toán: mặc định tiền tố `DH`, nội dung `DH1234` ứng với đơn #1234. 5. Đặt thử một đơn giá trị nhỏ, chọn TinoPay, quét QR và chuyển khoản: sau vài giây đơn tự chuyển trạng thái, có ghi chú "TinoPay: Đã nhận thanh toán…". Website đã kết nối chỉ được xem thông tin tài khoản ngân hàng, tài khoản ảo; tạo webhook trỏ về chính website đó; xem và cập nhật cấu trúc mã thanh toán. Website không xem được mật khẩu và không chuyển được tiền. | Tuỳ chọn trong plugin | Ý nghĩa | | --- | --- | | Tiền tố mã thanh toán | phải trùng Cài đặt → Cấu trúc mã thanh toán trên TinoPay | | Trạng thái đơn khi hoàn tất | trạng thái gán cho đơn khi nhận đủ tiền (mặc định Đang xử lý) | | Thông báo thành công | nội dung hiện cho khách sau khi thanh toán | | Chế độ tải xuống | sản phẩm số: hiện link tải ngay sau khi thanh toán | | Hiển thị tên ngân hàng | tên viết tắt, tên đầy đủ hoặc cả hai | Quản lý kết nối: web TinoPay → Tích hợp → WordPress, mục Website đã kết nối liệt kê website và thời điểm dùng gần nhất. Ngắt kết nối thu hồi quyền ngay, website phải kết nối lại; webhook đã tạo vẫn giữ, quản lý ở trang Webhooks. ### Cấu hình plugin thủ công Không dùng Kết nối TinoPay (OAuth) thì cấu hình tay: 1. Trong plugin: điền ngân hàng, số tài khoản (hoặc số tài khoản ảo), chủ tài khoản, tiền tố mã thanh toán và một API Key tự đặt (chỉ chữ và số, tối thiểu 10 ký tự). 2. Trên TinoPay → Tích hợp → Webhooks → Thêm webhook: URL `https:///wp-json/tinopay-gateway/v2/add-payment`, Token đúng API Key ở bước 1, Sự kiện Tiền vào, bật Bỏ qua nếu không có mã thanh toán. 3. Trên TinoPay → Cài đặt → Cấu trúc mã thanh toán: thêm tiền tố trùng plugin, độ dài hậu tố đủ chứa mã đơn hàng (ví dụ 1–10, kiểu Chữ và số hoặc Chỉ số). | Hiện tượng | Nguyên nhân thường gặp | | --- | --- | | khách chuyển khoản nhưng đơn không đổi trạng thái | nội dung chuyển khoản thiếu, sai mã `DH`; tiền tố plugin khác cấu trúc mã trên TinoPay; webhook đang tạm dừng | | lịch sử webhook báo `Invalid API Key` | token của webhook trên TinoPay khác API Key trong plugin (cấu hình thủ công) | | lịch sử webhook báo `Order not found` | mã trích được không khớp đơn nào: kiểm lại độ dài hậu tố trong cấu trúc mã thanh toán | | đơn ghi chú "thanh toán THIẾU/THỪA" | khách chuyển sai số tiền: đơn giữ nguyên trạng thái để bạn xử lý | | bấm Kết nối TinoPay báo lỗi | website chưa chạy HTTPS, hoặc phiên kết nối quá 15 phút: bấm lại | | không thấy mã QR ở trang cảm ơn | chưa chọn tài khoản ngân hàng, tài khoản ảo trong cài đặt plugin | Chi tiết từng lần gửi (mã HTTP, dữ liệu gửi đi, phản hồi của website) ở web TinoPay → Tích hợp → Lịch sử webhook. ## HostBill Module thanh toán TinoPay cho HostBill hiện mã VietQR ngay trên hoá đơn và tự ghi nhận thanh toán khi khách chuyển khoản: hoá đơn chuyển sang Paid sau vài giây, không cần đối soát tay. Module dùng [webhook](/docs/tinopay-webhook): mỗi giao dịch tiền vào có mã hoá đơn trong nội dung chuyển khoản được gửi về HostBill. 1. Khách mở hoá đơn trên HostBill, chọn TinoPay; hoá đơn hiện mã VietQR, nội dung `` (ví dụ `TNG2026`). 2. Khách chuyển khoản; TinoPay trích mã thanh toán `TNG2026`. 3. Webhook gửi về HostBill; module ghi nhận giao dịch, hoá đơn chuyển sang Paid. - Chuyển đủ tiền: giao dịch được thêm vào hoá đơn, hoá đơn chuyển sang Paid. - Chuyển thiếu hoặc dư: mặc định bỏ qua; bật Allow lower / higher amount nếu vẫn muốn ghi nhận. - Trang hoá đơn của khách tự tải lại khi hoá đơn đã thanh toán. Yêu cầu: quyền cài module thanh toán cho HostBill (thư mục `includes/modules/Payment/`); tài khoản TinoPay và ít nhất một tài khoản ngân hàng đã kết nối; với BIDV dùng tài khoản ảo nhận tiền. ### Cài module 1. [Tải module HostBill TinoPay (.zip)](https://pay.tino.vn/downloads/hostbill-tinopay.zip), giải nén vào thư mục module thanh toán của HostBill, được cấu trúc như khối dưới. 2. HostBill Admin → Settings → Modules → Payment Modules → kích hoạt TinoPay - Quét QR Code chuyển khoản. Ghi lại ID module, dùng cho URL webhook ở bước 4. 3. Cấu hình module theo bảng dưới. 4. Trên TinoPay: Cài đặt → Cấu trúc mã thanh toán, thêm tiền tố trùng Payment Code Prefix (ví dụ `TNG`), kiểu hậu tố Chỉ số, độ dài đủ chứa mã hoá đơn (ví dụ 1–10). Rồi Tích hợp → Webhooks → Thêm webhook theo bảng cuối mục này; có thể bật Bỏ qua nếu không có mã thanh toán để chỉ gửi giao dịch có mã hoá đơn. 5. Kiểm tra: tạo một hoá đơn nhỏ, chọn TinoPay; hoá đơn hiện mã QR là module đã chạy. Chuyển khoản thử: vài giây sau hoá đơn chuyển sang Paid. Chi tiết từng lần gửi ở Tích hợp → Lịch sử webhook trên TinoPay. ```text includes/modules/Payment/tinopay/class.tinopay.php includes/modules/Payment/tinopay/user/class.tinopay_controller.php ``` | Trường của module | Mô tả | | --- | --- | | TinoPay URL | `https://pay.tino.vn` | | Bank Info | mỗi dòng một tài khoản nhận tiền, dạng ở khối dưới; với BIDV điền số tài khoản ảo; để trống tối thiểu, tối đa là không giới hạn; nhiều dòng thì khách được chọn ngân hàng | | Payment Code Prefix | tiền tố nội dung chuyển khoản, ví dụ `TNG` → nội dung `TNG2026` cho hoá đơn 2026 | | Template QR | khung TinoPay kèm logo ngân hàng, hoặc chỉ hiện mã QR | | Webhook Token | chuỗi bí mật, phải trùng Token xác thực của webhook trên TinoPay | | Allow lower / higher amount | cho phép ghi nhận khi khách chuyển thiếu, dư so với hoá đơn | | Periodic invoice status check interval | chu kỳ trang hoá đơn kiểm tra đã thanh toán chưa, 1–10 giây, mặc định 3 | ```text mã_ngân_hàng|tên_chủ_tài_khoản|số_tài_khoản|số_tiền_tối_thiểu|số_tiền_tối_đa BIDV|CONG TY ABC|9624QA01|| ``` | Webhook trên TinoPay | Giá trị | | --- | --- | | URL nhận webhook | `https://<địa-chỉ-hostbill>/index.php?cmd=callback&module=` | | Tài khoản ngân hàng | tài khoản đã khai ở Bank Info (BIDV: chọn tài khoản ảo) | | Token xác thực | trùng Webhook Token của module | | Sự kiện | Tiền vào | ### Webhook gửi về HostBill HostBill nhận đúng [request webhook](/docs/tinopay-webhook#request-tinopay-gui) chung của TinoPay. Module lấy mã hoá đơn từ `code` (trống thì tìm trong `content`), bỏ tiền tố và InvoicePrefix của HostBill, kiểm số tiền rồi thêm giao dịch vào hoá đơn với mã giao dịch là `transaction_id`, nên gửi lại cùng giao dịch không bị ghi trùng. | Kết quả | Mã HTTP module trả | | --- | --- | | ghi nhận thành công | 201 | | bỏ qua: giao dịch đã ghi nhận, tiền ra, không có mã hoá đơn, không thấy hoá đơn, chuyển thiếu, dư (khi không cho phép) | 200 | | sai token | 401 | | dữ liệu không hợp lệ | 400 | TinoPay tự gửi lại webhook khi nhận mã khác 2xx: xem [Phản hồi và thử lại](/docs/tinopay-webhook#phan-hoi-va-thu-lai). | Hiện tượng | Nguyên nhân thường gặp | | --- | --- | | hoá đơn không hiện QR | Bank Info sai định dạng, hoặc số tiền hoá đơn nằm ngoài khoảng tối thiểu, tối đa của mọi dòng | | lịch sử webhook báo `401` | Webhook Token trên HostBill khác Token xác thực của webhook trên TinoPay | | lịch sử webhook báo `200` nhưng hoá đơn chưa Paid | xem `message` trong phản hồi: thiếu mã hoá đơn (tiền tố trên TinoPay khác Payment Code Prefix), chuyển thiếu, dư, hoặc sai mã hoá đơn | | webhook không gửi tới HostBill | webhook chọn sai tài khoản, tài khoản ảo; sự kiện không phải Tiền vào; hoặc URL sai ID module | ## Sapo Tự xác nhận thanh toán chuyển khoản cho đơn hàng trên website bán hàng Sapo: trang cảm ơn hiện mã VietQR kèm nội dung chuyển khoản; khách chuyển xong, vài giây sau đơn trên Sapo được ghi nhận đã thanh toán. 1. Khách đặt hàng, chọn Chuyển khoản ngân hàng; trang cảm ơn hiện mã VietQR, nội dung `DH`. 2. Khách chuyển khoản; TinoPay trích số đơn từ nội dung chuyển khoản. 3. TinoPay gọi Sapo Admin API ghi nhận thanh toán cho đơn; đơn chuyển sang Đã thanh toán. - Chuyển đủ tiền (hoặc dư): TinoPay ghi nhận thanh toán bằng đúng tổng tiền của đơn. - Chuyển thiếu: đơn giữ nguyên, TinoPay ghi lại ở mục Đối soát gần đây để bạn xử lý. - Đơn đã thanh toán hoặc đã huỷ: bỏ qua, không ghi nhận trùng. - Trang cảm ơn tự đổi sang "Đã nhận … cho đơn …" khi đơn được ghi nhận. Yêu cầu: website bán hàng Sapo (quản trị dạng `https://ten-cua-hang.mysapo.net/admin`), chưa hỗ trợ Sapo Omni / POS; tài khoản TinoPay và ít nhất một tài khoản ngân hàng đã kết nối; với BIDV cần chọn tài khoản ảo nhận tiền. ### Cài đặt Sapo 1. Sapo Admin → Ứng dụng → Ứng dụng riêng → Tạo ứng dụng riêng, đặt tên (ví dụ `TinoPay`). Phân quyền: dòng Đơn hàng, giao dịch và vận chuyển chọn Đọc và ghi, quyền khác Không cho phép. Bấm Lưu, sao chép API Key và API Secret. 2. Web TinoPay → Tích hợp → Sapo → Thêm cửa hàng, điền theo bảng dưới. TinoPay kiểm kết nối tới Sapo trước khi lưu; bấm Kiểm tra kết nối để thử trước. 3. Sapo Admin → Cấu hình → Phương thức thanh toán → Phương thức thanh toán thủ công → Thêm phương thức. Loại: Chuyển khoản. Tên cần có chữ "Chuyển khoản", ví dụ `Chuyển khoản ngân hàng (Tự động xác nhận)`: trang cảm ơn chỉ hiện QR cho đơn chọn phương thức chuyển khoản, không hiện cho COD. Hướng dẫn thanh toán, ví dụ: "Quét mã QR ở trang hoàn tất đơn hàng, giữ nguyên nội dung chuyển khoản. Đơn được xác nhận tự động sau vài giây." Bấm Lưu. 4. Trên TinoPay, ở thẻ cửa hàng, bấm Copy tại Mã nhúng trang thanh toán. Trong Sapo Admin → Cấu hình → Trang thanh toán → mục Xử lý đơn hàng, dán vào ô Nội dung thông báo thêm (hoặc Nội dung chân trang thanh toán) rồi Lưu. 5. Kiểm tra: đặt thử một đơn, chọn phương thức chuyển khoản ở bước 3; trang hoàn tất đơn hàng hiện QR là cấu hình đã đúng. Chuyển khoản thử một khoản nhỏ: đơn trên Sapo chuyển sang Đã thanh toán và dòng đối soát hiện ở trang Tích hợp → Sapo. | Trường khi thêm cửa hàng | Mô tả | | --- | --- | | Đặt tên cho tích hợp | tên tuỳ ý, ví dụ `Sapo Web` | | Ngân hàng nhận thanh toán | tài khoản ngân hàng hiện trên QR; với BIDV chọn thêm tài khoản ảo, chỉ giao dịch vào tài khoản ảo này mới được đối soát | | Tiền tố mã thanh toán | chọn trong các tiền tố đã khai ở Cài đặt → Cấu trúc mã thanh toán (ví dụ `DH`); nội dung chuyển khoản là tiền tố + số đơn Sapo, ví dụ đơn #1001 → `DH1001` | | URL cửa hàng | dạng `https://ten-cua-hang.mysapo.net` (địa chỉ `.mysapo.net`, không dùng tên miền riêng) | | API Key / API Secret | lấy ở bước 1; secret được mã hoá khi lưu, khi sửa để trống thì giữ secret cũ | | Tùy chỉnh cấu hình tham số | tham số của giao dịch TinoPay tạo trên đơn Sapo, mục dưới | | Trạng thái | Kích hoạt, Tạm dừng | Mã nhúng có dạng dưới (dán nguyên mã đã sao chép, gồm cả địa chỉ script). Mã chỉ chứa khoá công khai của cửa hàng, không chứa API Key, API Secret. Trang cảm ơn chỉ hiện QR cho đơn tạo trong 7 ngày gần nhất. ```html ``` ### Tham số giao dịch Sapo Khi khách chuyển đủ tiền, TinoPay tạo một giao dịch thanh toán trên đơn qua [Sapo Transaction API](https://support.sapo.vn/transaction#create) (`POST /admin/orders/{id}/transactions.json`) với số tiền bằng tổng đơn. Ba tham số quyết định giao dịch đó: | Tham số | Giá trị | Ý nghĩa | | --- | --- | --- | | `kind` | `capture` (mặc định), `sale`, `authorization` | loại giao dịch; `capture` là thu tiền cho đơn đã đặt, hợp với đơn chuyển khoản thủ công | | `source_name` | Không tùy chỉnh, `web`, `pos`, `iphone`, `android` | nguồn giao dịch; để trống thì Sapo tự đặt | | `status` | Không tùy chỉnh, `success`, `pending`, `failure`, `error` | trạng thái giao dịch; để trống thì Sapo tự đặt | Để mặc định (`capture`, không tùy chỉnh) hợp với đa số cửa hàng; chỉ đổi khi đơn trên Sapo chưa chuyển sang Đã thanh toán sau khi ghi nhận. ### Đối soát Sapo Trang Tích hợp → Sapo hiện 20 giao dịch có mã đơn gần nhất: | Trạng thái | Ý nghĩa | | --- | --- | | Đã ghi nhận | đã ghi nhận thanh toán cho đơn trên Sapo | | Chuyển thiếu | số tiền nhỏ hơn tổng đơn, chưa ghi nhận; xử lý thủ công trên Sapo | | Đã thanh toán trước | đơn đã ở trạng thái đã thanh toán, bỏ qua | | Không thấy đơn | không có đơn với số đơn trong nội dung chuyển khoản | | Đơn đã huỷ | đơn đã huỷ, không ghi nhận | | Lỗi | Sapo từ chối hoặc không kết nối được (sai API Key, API Secret, ứng dụng bị xoá…) | Bấm Gửi lại hook ở trang chi tiết giao dịch để đối soát lại sau khi sửa cấu hình; đơn đã thanh toán không bị ghi nhận trùng. | Hiện tượng | Nguyên nhân thường gặp | | --- | --- | | trang cảm ơn không hiện QR | chưa dán mã nhúng, tích hợp đang tạm dừng, hoặc tên phương thức thanh toán trên Sapo không có chữ "Chuyển khoản" | | lưu tích hợp báo sai API Key, API Secret | ứng dụng riêng chưa có quyền Đọc và ghi đơn hàng, hoặc sao chép thiếu ký tự | | khách đã chuyển nhưng đơn chưa xác nhận | nội dung chuyển khoản thiếu mã đơn (`DH1001`), chuyển thiếu tiền, hoặc chuyển vào tài khoản, tài khoản ảo khác tài khoản đã chọn; xem mục Đối soát gần đây | --- # API Reference 166 route của gateway `https://api.tino.vn/v1` và API của dịch vụ TinoPay, Tino Uptime, TinoPage Builder, theo sản phẩm. Mỗi route một trang: tham số, ví dụ cURL, JavaScript, PHP, SDK, mẫu response. Xác thực, cách gửi tham số và mã lỗi chung: [Gọi API Tino](/docs/api). Bản máy đọc: [/openapi.json](/openapi.json). ## Identity & SSO ### Tài khoản | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/clientarea` | [Tổng quan tài khoản](/docs/api/get-clientarea) | `profile:read` | | `GET` | `/v1/clientarea/nav/service` | [Danh mục dịch vụ](/docs/api/get-clientarea-nav-service) | `profile:read` | | `POST` | `/v1/clientarea/search/@query` | [Tìm dịch vụ, sản phẩm](/docs/api/post-clientarea-search-query) | `profile:read` | | `GET` | `/v1/clientarea/statuses` | [Danh sách trạng thái](/docs/api/get-clientarea-statuses) | `profile:read` | | `GET` | `/v1/contact` | [Danh sách liên hệ](/docs/api/get-contact) | `profile:read` | | `GET` | `/v1/contact/@id` | [Chi tiết liên hệ](/docs/api/get-contact-id) | `profile:read` | | `GET` | `/v1/contact/privileges` | [Quyền có thể cấp cho liên hệ](/docs/api/get-contact-privileges) | `profile:read` | | `GET` | `/v1/contacts` | [Danh sách liên hệ (contacts)](/docs/api/get-contacts) | `profile:read` | | `GET` | `/v1/details` | [Thông tin tài khoản](/docs/api/get-details) | `profile:read` | | `GET` | `/v1/notifications` | [Danh sách thông báo](/docs/api/get-notifications) | `profile:read` | | `PUT` | `/v1/notifications/@id/ack` | [Đánh dấu đã đọc thông báo](/docs/api/put-notifications-id-ack) | `profile:write` | | `GET` | `/v1/notifications/new` | [Thông báo chưa đọc](/docs/api/get-notifications-new) | `profile:read` | ## Domains & DNS ### Tên miền | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/domain` | [Danh sách tên miền](/docs/api/get-domain) | `domains:read` | | `GET` | `/v1/domain/@id` | [Chi tiết tên miền](/docs/api/get-domain-id) | `domains:read` | | `GET` | `/v1/domain/@id/autorenew` | [Xem tự gia hạn tên miền](/docs/api/get-domain-id-autorenew) | `domains:read` | | `PUT` | `/v1/domain/@id/autorenew` | [Bật/tắt tự gia hạn tên miền](/docs/api/put-domain-id-autorenew) | `domains:write` | | `GET` | `/v1/domain/@id/contact` | [Xem liên hệ tên miền](/docs/api/get-domain-id-contact) | `domains:read` | | `PUT` | `/v1/domain/@id/contact` | [Đổi liên hệ (chủ thể) tên miền](/docs/api/put-domain-id-contact) | `domains:owner` | | `GET` | `/v1/domain/@id/dnssec` | [Danh sách khoá DNSSEC](/docs/api/get-domain-id-dnssec) | `domains:read` | | `PUT` | `/v1/domain/@id/dnssec` | [Thêm khoá DNSSEC](/docs/api/put-domain-id-dnssec) | `domains:write` | | `DELETE` | `/v1/domain/@id/dnssec/@key` | [Xoá khoá DNSSEC](/docs/api/delete-domain-id-dnssec-key) | `domains:write` | | `GET` | `/v1/domain/@id/dnssec/flags` | [Tham số DNSSEC hỗ trợ](/docs/api/get-domain-id-dnssec-flags) | `domains:read` | | `GET` | `/v1/domain/@id/emforwarding` | [Xem chuyển tiếp email](/docs/api/get-domain-id-emforwarding) | `domains:read` | | `PUT` | `/v1/domain/@id/emforwarding` | [Cập nhật chuyển tiếp email](/docs/api/put-domain-id-emforwarding) | `domains:write` | | `GET` | `/v1/domain/@id/epp` | [Lấy mã chuyển tên miền (EPP)](/docs/api/get-domain-id-epp) | `domains:owner` | | `PUT` | `/v1/domain/@id/forwarding` | [Cập nhật chuyển hướng tên miền](/docs/api/put-domain-id-forwarding) | `domains:write` | | `PUT` | `/v1/domain/@id/idprotection` | [Bật/tắt ẩn thông tin chủ thể](/docs/api/put-domain-id-idprotection) | `domains:write` | | `GET` | `/v1/domain/@id/invoices` | [Hoá đơn của tên miền](/docs/api/get-domain-id-invoices) | `domains:read` | | `GET` | `/v1/domain/@id/ns` | [Xem nameserver](/docs/api/get-domain-id-ns) | `domains:read` | | `PUT` | `/v1/domain/@id/ns` | [Đổi nameserver](/docs/api/put-domain-id-ns) | `domains:write` | | `GET` | `/v1/domain/@id/reg` | [Nameserver riêng đã đăng ký](/docs/api/get-domain-id-reg) | `domains:read` | | `POST` | `/v1/domain/@id/reg` | [Quản lý nameserver riêng](/docs/api/post-domain-id-reg) | `domains:write` | | `GET` | `/v1/domain/@id/reglock` | [Xem khoá tên miền](/docs/api/get-domain-id-reglock) | `domains:read` | | `PUT` | `/v1/domain/@id/reglock` | [Bật/tắt khoá tên miền](/docs/api/put-domain-id-reglock) | `domains:write` | | `POST` | `/v1/domain/@id/renew` | [Gia hạn tên miền](/docs/api/post-domain-id-renew) | `domains:write` | | `GET` | `/v1/domain/@id/sync` | [Đồng bộ tên miền](/docs/api/get-domain-id-sync) | `domains:write` | | `POST` | `/v1/domain/lookup` | [Kiểm tra tên miền còn trống](/docs/api/post-domain-lookup) | `domains:read` | | `GET` | `/v1/domain/name/@name` | [Chi tiết tên miền theo tên](/docs/api/get-domain-name-name) | `domains:read` | | `GET` | `/v1/domain/order` | [Đuôi tên miền có thể đăng ký](/docs/api/get-domain-order) | `domains:read` | | `POST` | `/v1/domain/order` | [Đặt mua tên miền](/docs/api/post-domain-order) | `domains:write` | | `GET` | `/v1/domain/order/@id/form` | [Thông tin bổ sung theo đuôi tên miền](/docs/api/get-domain-order-id-form) | `domains:read` | | `GET` | `/v1/domains` | [Danh sách tên miền (phân trang)](/docs/api/get-domains) | `domains:read` | | `GET` | `/v1/domains/@id/registrant` | [Xem chủ thể tên miền đang chờ](/docs/api/get-domains-id-registrant) | `domains:registrant` | | `PUT` | `/v1/domains/@id/registrant` | [Lưu chủ thể tên miền đang chờ](/docs/api/put-domains-id-registrant) | `domains:registrant` | | `GET` | `/v1/domains/pending` | [Tên miền chờ hoàn tất hồ sơ](/docs/api/get-domains-pending) | `domains:registrant` | | `GET` | `/v1/registrants` | [Chủ thể đã dùng](/docs/api/get-registrants) | `domains:registrant` | | `GET` | `/v1/whois/@domain` | [Tra whois tên miền (bằng token)](/docs/api/get-v1-whois-domain) | `domains:read` | | `GET` | `/whois/@domain` | [Tra whois tên miền](/docs/api/get-whois-domain) | — | ### DNS | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/dns` | [Danh sách vùng DNS](/docs/api/get-dns) | `dns:read` | | `GET` | `/v1/dns/templates` | [Mẫu bản ghi DNS](/docs/api/get-dns-templates) | `dns:read` | | `GET` | `/v1/domain/@id/dns` | [Bản ghi DNS của tên miền](/docs/api/get-domain-id-dns) | `dns:read` | | `POST` | `/v1/domain/@id/dns` | [Thêm bản ghi DNS cho tên miền](/docs/api/post-domain-id-dns) | `dns:write` | | `PUT` | `/v1/domain/@id/dns/@index` | [Sửa bản ghi DNS của tên miền](/docs/api/put-domain-id-dns-index) | `dns:write` | | `DELETE` | `/v1/domain/@id/dns/@index` | [Xoá bản ghi DNS của tên miền](/docs/api/delete-domain-id-dns-index) | `dns:write` | | `GET` | `/v1/domain/@id/dns/types` | [Loại bản ghi DNS hỗ trợ](/docs/api/get-domain-id-dns-types) | `dns:read` | | `GET` | `/v1/service/@service_id/dns` | [Vùng DNS của dịch vụ](/docs/api/get-service-service-id-dns) | `dns:read` | | `POST` | `/v1/service/@service_id/dns` | [Thêm vùng DNS](/docs/api/post-service-service-id-dns) | `dns:write` | | `GET` | `/v1/service/@service_id/dns/@zone_id` | [Chi tiết vùng DNS](/docs/api/get-service-service-id-dns-zone-id) | `dns:read` | | `PUT` | `/v1/service/@service_id/dns/@zone_id` | [Sửa vùng DNS](/docs/api/put-service-service-id-dns-zone-id) | `dns:write` | | `DELETE` | `/v1/service/@service_id/dns/@zone_id` | [Xoá vùng DNS](/docs/api/delete-service-service-id-dns-zone-id) | `dns:write` | | `GET` | `/v1/service/@service_id/dns/@zone_id/dnssec` | [Xem DNSSEC của vùng DNS](/docs/api/get-service-service-id-dns-zone-id-dnssec) | `dns:read` | | `PUT` | `/v1/service/@service_id/dns/@zone_id/dnssec` | [Bật/tắt DNSSEC của vùng DNS](/docs/api/put-service-service-id-dns-zone-id-dnssec) | `dns:write` | | `POST` | `/v1/service/@service_id/dns/@zone_id/records` | [Thêm bản ghi DNS](/docs/api/post-service-service-id-dns-zone-id-records) | `dns:write` | | `PUT` | `/v1/service/@service_id/dns/@zone_id/records/@record_id` | [Sửa bản ghi DNS](/docs/api/put-service-service-id-dns-zone-id-records-record-id) | `dns:write` | | `DELETE` | `/v1/service/@service_id/dns/@zone_id/records/@record_id` | [Xoá bản ghi DNS](/docs/api/delete-service-service-id-dns-zone-id-records-record-id) | `dns:write` | ## Cloud & Hosting ### Dịch vụ | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service` | [Danh sách dịch vụ](/docs/api/get-service) | `services:read` | | `GET` | `/v1/service/@id` | [Chi tiết dịch vụ](/docs/api/get-service-id) | `services:read` | | `POST` | `/v1/service/@id/cancel` | [Yêu cầu huỷ dịch vụ](/docs/api/post-service-id-cancel) | `services:write` | | `GET` | `/v1/service/@id/cycle` | [Các chu kỳ thanh toán](/docs/api/get-service-id-cycle) | `services:read` | | `POST` | `/v1/service/@id/cycle` | [Đổi chu kỳ thanh toán](/docs/api/post-service-id-cycle) | `services:write` | | `GET` | `/v1/service/@id/emails` | [Tài khoản email của hosting](/docs/api/get-service-id-emails) | `services:read` | | `GET` | `/v1/service/@id/invoices` | [Hoá đơn của dịch vụ](/docs/api/get-service-id-invoices) | `services:read` | | `GET` | `/v1/service/@id/label` | [Xem nhãn dịch vụ](/docs/api/get-service-id-label) | `services:read` | | `POST` | `/v1/service/@id/label` | [Đặt nhãn dịch vụ](/docs/api/post-service-id-label) | `services:write` | | `POST` | `/v1/service/@id/manualrenew` | [Tạo hoá đơn gia hạn dịch vụ](/docs/api/post-service-id-manualrenew) | `services:write` | | `GET` | `/v1/service/@id/methods` | [Thao tác hỗ trợ của dịch vụ](/docs/api/get-service-id-methods) | `services:read` | | `POST` | `/v1/service/@id/renew` | [Gia hạn dịch vụ](/docs/api/post-service-id-renew) | `services:write` | | `GET` | `/v1/service/@id/upgrade` | [Tuỳ chọn nâng cấp](/docs/api/get-service-id-upgrade) | `services:read` | | `POST` | `/v1/service/@id/upgrade` | [Báo giá hoặc yêu cầu nâng cấp](/docs/api/post-service-id-upgrade) | `services:write` | | `GET` | `/v1/service/@id/widgets` | [Tiện ích của dịch vụ](/docs/api/get-service-id-widgets) | `services:read` | | `GET` | `/v1/service/cpanel2/@id/statistics` | [Thống kê cPanel](/docs/api/get-service-cpanel2-id-statistics) | `services:read` | | `POST` | `/v1/service/cpanel2/@id/unblock` | [Gỡ chặn IP trên cPanel](/docs/api/post-service-cpanel2-id-unblock) | `services:write` | | `GET` | `/v1/services/@cid` | [Dịch vụ theo danh mục](/docs/api/get-services-cid) | `services:read` | | `GET` | `/v1/services/active` | [Dịch vụ đang hoạt động](/docs/api/get-services-active) | `services:read` | ### Máy chủ VPS | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service/@id/networks` | [Mạng và dải IP](/docs/api/get-service-id-networks) | `services:read` | | `GET` | `/v1/service/@id/resources` | [Tài nguyên VPS](/docs/api/get-service-id-resources) | `services:read` | | `GET` | `/v1/service/@id/templates` | [Mẫu hệ điều hành](/docs/api/get-service-id-templates) | `services:read` | | `GET` | `/v1/service/@id/vms` | [Danh sách máy ảo](/docs/api/get-service-id-vms) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid` | [Chi tiết máy ảo](/docs/api/get-service-id-vms-vmid) | `services:read` | | `POST` | `/v1/service/@id/vms/@vmid/hostname` | [Đổi hostname máy ảo](/docs/api/post-service-id-vms-vmid-hostname) | `services:write` | | `GET` | `/v1/service/@id/vms/@vmid/interfaces` | [Card mạng của máy ảo](/docs/api/get-service-id-vms-vmid-interfaces) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/interfaces/@iface` | [Chi tiết card mạng](/docs/api/get-service-id-vms-vmid-interfaces-iface) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/ippool` | [Dải IP của máy ảo](/docs/api/get-service-id-vms-vmid-ippool) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/ips` | [IP của máy ảo](/docs/api/get-service-id-vms-vmid-ips) | `services:read` | | `POST` | `/v1/service/@id/vms/@vmid/reboot` | [Khởi động lại máy ảo](/docs/api/post-service-id-vms-vmid-reboot) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/reset` | [Reset máy ảo](/docs/api/post-service-id-vms-vmid-reset) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/shutdown` | [Tắt máy ảo](/docs/api/post-service-id-vms-vmid-shutdown) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/start` | [Bật máy ảo](/docs/api/post-service-id-vms-vmid-start) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/stop` | [Dừng máy ảo](/docs/api/post-service-id-vms-vmid-stop) | `services:write` | | `GET` | `/v1/service/@id/vms/@vmid/traffic` | [Lưu lượng mạng của máy ảo](/docs/api/get-service-id-vms-vmid-traffic) | `services:read` | ### Chứng chỉ SSL | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/certificate` | [Danh sách chứng chỉ SSL](/docs/api/get-certificate) | `services:read` | | `GET` | `/v1/certificate/@id` | [Chi tiết chứng chỉ SSL](/docs/api/get-certificate-id) | `services:read` | | `GET` | `/v1/certificate/@id/crt` | [Tải chứng chỉ](/docs/api/get-certificate-id-crt) | `services:read` | | `GET` | `/v1/certificate/order` | [Chứng chỉ có thể mua](/docs/api/get-certificate-order) | `services:read` | | `POST` | `/v1/certificate/order` | [Đặt mua chứng chỉ SSL](/docs/api/post-certificate-order) | `services:write` | | `GET` | `/v1/certificate/order/@product_id/software` | [Phần mềm máy chủ cho chứng chỉ](/docs/api/get-certificate-order-product-id-software) | `services:read` | | `GET` | `/v1/certificates` | [Danh sách dịch vụ SSL (certificates)](/docs/api/get-certificates) | `services:read` | ## Billing ### Hoá đơn & thanh toán | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/addfunds` | [Thông tin nạp tiền](/docs/api/get-addfunds) | `billing:read` | | `POST` | `/v1/addfunds` | [Nạp tiền](/docs/api/post-addfunds) | `billing:write` | | `GET` | `/v1/balance` | [Số dư tài khoản](/docs/api/get-balance) | `billing:read` | | `GET` | `/v1/billing/@invoice_id/pay/@gateway_id` | [Link thanh toán hoá đơn](/docs/api/get-billing-invoice-id-pay-gateway-id) | `billing:write` | | `POST` | `/v1/billing/addfunds` | [Nạp tiền (billing)](/docs/api/post-billing-addfunds) | `billing:write` | | `GET` | `/v1/billing/creditlogs` | [Lịch sử số dư tín dụng](/docs/api/get-billing-creditlogs) | `billing:read` | | `POST` | `/v1/billing/creditvoucher` | [Dùng mã nạp tiền](/docs/api/post-billing-creditvoucher) | `billing:write` | | `GET` | `/v1/estimate/@id/pdf` | [Tải PDF báo giá](/docs/api/get-estimate-id-pdf) | `billing:read` | | `GET` | `/v1/estimates` | [Danh sách báo giá](/docs/api/get-estimates) | `billing:read` | | `GET` | `/v1/estimates/@id` | [Chi tiết báo giá](/docs/api/get-estimates-id) | `billing:read` | | `GET` | `/v1/invoice` | [Danh sách hoá đơn](/docs/api/get-invoice) | `billing:read` | | `GET` | `/v1/invoice/@id` | [Chi tiết hoá đơn](/docs/api/get-invoice-id) | `billing:read` | | `DELETE` | `/v1/invoice/@id` | [Xoá hoá đơn](/docs/api/delete-invoice-id) | `billing:write` | | `POST` | `/v1/invoice/@id/credit` | [Trả hoá đơn bằng số dư](/docs/api/post-invoice-id-credit) | `billing:write` | | `GET` | `/v1/invoice/@id/pdf` | [Tải PDF hoá đơn](/docs/api/get-invoice-id-pdf) | `billing:read` | | `GET` | `/v1/invoices` | [Danh sách hoá đơn (phân trang)](/docs/api/get-invoices) | `billing:read` | | `GET` | `/v1/invoices/due` | [Hoá đơn đến hạn](/docs/api/get-invoices-due) | `billing:read` | | `POST` | `/v1/invoices/payall` | [Thanh toán gộp hoá đơn](/docs/api/post-invoices-payall) | `billing:write` | | `GET` | `/v1/payment` | [Phương thức thanh toán](/docs/api/get-payment) | `billing:read` | | `GET` | `/v1/payment/fees` | [Phí phương thức thanh toán](/docs/api/get-payment-fees) | `billing:read` | ### Đặt hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/v1/carts` | [Tạo giỏ hàng](/docs/api/post-carts) | `orders:write` | | `GET` | `/v1/carts/@uuid` | [Xem giỏ hàng](/docs/api/get-carts-uuid) | `orders:write` | | `PUT` | `/v1/carts/@uuid` | [Sửa giỏ hàng](/docs/api/put-carts-uuid) | `orders:write` | | `POST` | `/v1/carts/@uuid/confirm` | [Chốt đơn từ giỏ](/docs/api/post-carts-uuid-confirm) | `orders:write` | | `GET` | `/v1/carts/latest` | [Giỏ hàng gần nhất](/docs/api/get-carts-latest) | `orders:write` | | `POST` | `/v1/order` | [Đặt mua nhiều dịch vụ](/docs/api/post-order) | `orders:write` | | `POST` | `/v1/order/@product_id` | [Đặt mua một dịch vụ](/docs/api/post-order-product-id) | `orders:write` | | `POST` | `/v1/quote` | [Báo giá đơn hàng](/docs/api/post-quote) | `orders:write` | ## TinoPay ### Merchant | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay` | [Thông tin merchant](/docs/api/tinopay-get-merchant) | — | | `PATCH` | `/service/@id/tinopay` | [Sửa thông tin merchant](/docs/api/tinopay-patch-merchant) | — | | `GET` | `/service/@id/tinopay/pay-codes` | [Cấu trúc mã thanh toán](/docs/api/tinopay-get-pay-codes) | — | | `PUT` | `/service/@id/tinopay/pay-codes` | [Lưu cấu trúc mã thanh toán](/docs/api/tinopay-put-pay-codes) | — | ### Tài khoản ngân hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/bank-accounts` | [Danh sách tài khoản ngân hàng](/docs/api/tinopay-get-bank-accounts) | — | | `GET` | `/service/@id/tinopay/bank-accounts/@bank` | [Chi tiết tài khoản ngân hàng](/docs/api/tinopay-get-bank-accounts-bank) | — | | `POST` | `/service/@id/tinopay/bank-links/bidv-business` | [Yêu cầu liên kết BIDV doanh nghiệp](/docs/api/tinopay-post-bank-links-bidv-business) | — | ### Tài khoản ảo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts` | [Danh sách tài khoản ảo (VA)](/docs/api/tinopay-get-bank-accounts-bank-virtual-accounts) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts` | [Tạo tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va/activate` | [Mở tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts-va-activate) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va/deactivate` | [Khoá tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts-va-deactivate) | — | | `DELETE` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va` | [Xoá tài khoản ảo](/docs/api/tinopay-delete-bank-accounts-bank-virtual-accounts-va) | — | ### Webhook | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/webhooks` | [Danh sách webhook](/docs/api/tinopay-get-webhooks) | — | | `POST` | `/service/@id/tinopay/webhooks` | [Tạo webhook](/docs/api/tinopay-post-webhooks) | — | | `GET` | `/service/@id/tinopay/webhooks/@webhook` | [Chi tiết webhook](/docs/api/tinopay-get-webhooks-webhook) | — | | `PATCH` | `/service/@id/tinopay/webhooks/@webhook` | [Sửa webhook](/docs/api/tinopay-patch-webhooks-webhook) | — | | `DELETE` | `/service/@id/tinopay/webhooks/@webhook` | [Xoá webhook](/docs/api/tinopay-delete-webhooks-webhook) | — | | `GET` | `/service/@id/tinopay/webhook-logs` | [Log webhook](/docs/api/tinopay-get-webhook-logs) | — | | `POST` | `/service/@id/tinopay/webhook-logs/@log/resend` | [Gửi lại log webhook](/docs/api/tinopay-post-webhook-logs-log-resend) | — | ### Giao dịch | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/transactions` | [Lịch sử giao dịch](/docs/api/tinopay-get-transactions) | — | | `GET` | `/service/@id/tinopay/transactions/summary` | [Tổng hợp giao dịch](/docs/api/tinopay-get-transactions-summary) | — | | `GET` | `/service/@id/tinopay/transactions/@transaction` | [Chi tiết giao dịch](/docs/api/tinopay-get-transactions-transaction) | — | | `POST` | `/service/@id/tinopay/transactions/@transaction/resend-webhook` | [Bắn lại webhook cho giao dịch](/docs/api/tinopay-post-transactions-transaction-resend-webhook) | — | ### Thông báo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/service/@id/tinopay/notification-apps/bot-info` | [Kiểm token bot](/docs/api/tinopay-post-notification-apps-bot-info) | — | | `POST` | `/service/@id/tinopay/notification-apps/find-chats` | [Tìm nơi nhận của bot](/docs/api/tinopay-post-notification-apps-find-chats) | — | | `POST` | `/service/@id/tinopay/notification-apps/test` | [Gửi tin thử](/docs/api/tinopay-post-notification-apps-test) | — | | `GET` | `/service/@id/tinopay/notification-apps` | [Danh sách ứng dụng thông báo](/docs/api/tinopay-get-notification-apps) | — | | `POST` | `/service/@id/tinopay/notification-apps` | [Tạo ứng dụng thông báo](/docs/api/tinopay-post-notification-apps) | — | | `GET` | `/service/@id/tinopay/notification-apps/@app` | [Chi tiết ứng dụng thông báo](/docs/api/tinopay-get-notification-apps-app) | — | | `PATCH` | `/service/@id/tinopay/notification-apps/@app` | [Sửa ứng dụng thông báo](/docs/api/tinopay-patch-notification-apps-app) | — | | `DELETE` | `/service/@id/tinopay/notification-apps/@app` | [Xoá ứng dụng thông báo](/docs/api/tinopay-delete-notification-apps-app) | — | ### Tích hợp Sapo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/service/@id/tinopay/sapo-integrations/test` | [Thử kết nối Sapo](/docs/api/tinopay-post-sapo-integrations-test) | — | | `GET` | `/service/@id/tinopay/sapo-integrations` | [Danh sách tích hợp Sapo](/docs/api/tinopay-get-sapo-integrations) | — | | `POST` | `/service/@id/tinopay/sapo-integrations` | [Tạo tích hợp Sapo](/docs/api/tinopay-post-sapo-integrations) | — | | `GET` | `/service/@id/tinopay/sapo-integrations/@integration` | [Chi tiết tích hợp Sapo](/docs/api/tinopay-get-sapo-integrations-integration) | — | | `PATCH` | `/service/@id/tinopay/sapo-integrations/@integration` | [Sửa tích hợp Sapo](/docs/api/tinopay-patch-sapo-integrations-integration) | — | | `DELETE` | `/service/@id/tinopay/sapo-integrations/@integration` | [Xoá tích hợp Sapo](/docs/api/tinopay-delete-sapo-integrations-integration) | — | | `GET` | `/service/@id/tinopay/sapo-order-logs` | [Nhật ký đối soát Sapo](/docs/api/tinopay-get-sapo-order-logs) | — | ### API token | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/api-tokens` | [Danh sách API token](/docs/api/tinopay-get-api-tokens) | — | | `POST` | `/service/@id/tinopay/api-tokens` | [Tạo API token](/docs/api/tinopay-post-api-tokens) | — | | `DELETE` | `/service/@id/tinopay/api-tokens/@token` | [Thu hồi API token](/docs/api/tinopay-delete-api-tokens-token) | — | ## Tino Uptime ### Gói Uptime | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime` | [Tổng quan gói Tino Uptime](/docs/api/uptime-get-overview) | — | | `GET` | `/service/@id/uptime/usage` | [Mức dùng so với hạn mức](/docs/api/uptime-get-usage) | — | ### Monitor | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/monitors` | [Danh sách monitor](/docs/api/uptime-get-monitors) | — | | `POST` | `/service/@id/uptime/monitors` | [Tạo monitor](/docs/api/uptime-post-monitors) | — | | `GET` | `/service/@id/uptime/monitors/@monitor` | [Chi tiết monitor](/docs/api/uptime-get-monitors-monitor) | — | | `PUT` | `/service/@id/uptime/monitors/@monitor` | [Sửa monitor](/docs/api/uptime-put-monitors-monitor) | — | | `DELETE` | `/service/@id/uptime/monitors/@monitor` | [Xoá monitor](/docs/api/uptime-delete-monitors-monitor) | — | | `POST` | `/service/@id/uptime/monitors/@monitor/pause` | [Tạm dừng monitor](/docs/api/uptime-post-monitors-monitor-pause) | — | | `POST` | `/service/@id/uptime/monitors/@monitor/resume` | [Chạy lại monitor](/docs/api/uptime-post-monitors-monitor-resume) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/uptime` | [Uptime của monitor](/docs/api/uptime-get-monitors-monitor-uptime) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/results` | [Kết quả kiểm của monitor](/docs/api/uptime-get-monitors-monitor-results) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/incidents` | [Sự cố của monitor](/docs/api/uptime-get-monitors-monitor-incidents) | — | ### Sự cố | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/incidents` | [Danh sách sự cố](/docs/api/uptime-get-incidents) | — | | `GET` | `/service/@id/uptime/incidents/@incident` | [Chi tiết sự cố](/docs/api/uptime-get-incidents-incident) | — | | `POST` | `/service/@id/uptime/incidents/@incident/ack` | [Xác nhận sự cố](/docs/api/uptime-post-incidents-incident-ack) | — | ### Kênh cảnh báo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/channels` | [Danh sách kênh cảnh báo](/docs/api/uptime-get-channels) | — | | `POST` | `/service/@id/uptime/channels` | [Tạo kênh cảnh báo](/docs/api/uptime-post-channels) | — | | `POST` | `/service/@id/uptime/channels/@channel/verify` | [Xác minh kênh cảnh báo](/docs/api/uptime-post-channels-channel-verify) | — | | `POST` | `/service/@id/uptime/channels/@channel/test` | [Gửi tin thử](/docs/api/uptime-post-channels-channel-test) | — | | `DELETE` | `/service/@id/uptime/channels/@channel` | [Xoá kênh cảnh báo](/docs/api/uptime-delete-channels-channel) | — | ## TinoPage Builder ### Tài khoản Builder | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/overview` | [Tổng quan tài khoản TinoPage Builder](/docs/api/builder-get-overview) | — | | `POST` | `/service/@id/builder/login` | [Vé đăng nhập một lần](/docs/api/builder-post-login) | — | ### Website | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites` | [Danh sách website](/docs/api/builder-get-sites) | — | | `GET` | `/service/@id/builder/sites/@site` | [Chi tiết website](/docs/api/builder-get-sites-site) | — | | `POST` | `/service/@id/builder/sites` | [Tạo website bằng AI](/docs/api/builder-post-sites) | — | | `GET` | `/service/@id/builder/site-creation` | [Tiến độ tạo website](/docs/api/builder-get-site-creation) | — | | `POST` | `/service/@id/builder/sites/@site/publish` | [Đăng website](/docs/api/builder-post-sites-site-publish) | — | | `POST` | `/service/@id/builder/sites/@site/unpublish` | [Tạm ngưng website](/docs/api/builder-post-sites-site-unpublish) | — | | `DELETE` | `/service/@id/builder/sites/@site` | [Xoá website](/docs/api/builder-delete-sites-site) | — | ### Tên miền riêng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites/@site/domains` | [Tên miền riêng của website](/docs/api/builder-get-sites-site-domains) | — | | `POST` | `/service/@id/builder/sites/@site/domains` | [Gắn tên miền riêng](/docs/api/builder-post-sites-site-domains) | — | | `POST` | `/service/@id/builder/sites/@site/domains/@hostname/verify` | [Kiểm tra lại DNS](/docs/api/builder-post-sites-site-domains-hostname-verify) | — | | `DELETE` | `/service/@id/builder/sites/@site/domains/@hostname` | [Gỡ tên miền riêng](/docs/api/builder-delete-sites-site-domains-hostname) | — | ### Liên hệ & đơn hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites/@site/leads` | [Liên hệ và đơn hàng](/docs/api/builder-get-sites-site-leads) | — | ## TinoWAF ### TinoWAF | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service/@id/waf/events` | [Tóm tắt sự kiện](/docs/api/get-service-id-waf-events) | `waf:read` | | `GET` | `/v1/service/@id/waf/ip-rules` | [Danh sách IP chặn, cho phép](/docs/api/get-service-id-waf-ip-rules) | `waf:read` | | `POST` | `/v1/service/@id/waf/ip-rules` | [Chặn hoặc cho phép IP](/docs/api/post-service-id-waf-ip-rules) | `waf:write` | | `DELETE` | `/v1/service/@id/waf/ip-rules/@rule` | [Xoá mục IP](/docs/api/delete-service-id-waf-ip-rules-rule) | `waf:write` | | `POST` | `/v1/service/@id/waf/ip-rules/apply` | [Áp lại luật IP](/docs/api/post-service-id-waf-ip-rules-apply) | `waf:write` | | `GET` | `/v1/service/@id/waf/overview` | [Tổng quan TinoWAF](/docs/api/get-service-id-waf-overview) | `waf:read` | | `GET` | `/v1/service/@id/waf/zones` | [Danh sách website](/docs/api/get-service-id-waf-zones) | `waf:read` | | `POST` | `/v1/service/@id/waf/zones` | [Thêm website](/docs/api/post-service-id-waf-zones) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone` | [Chi tiết website](/docs/api/get-service-id-waf-zones-zone) | `waf:read` | | `DELETE` | `/v1/service/@id/waf/zones/@zone` | [Xoá website](/docs/api/delete-service-id-waf-zones-zone) | `waf:write` | | `POST` | `/v1/service/@id/waf/zones/@zone/check` | [Kiểm tra DNS ngay](/docs/api/post-service-id-waf-zones-zone-check) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone/events` | [Nhật ký sự kiện của website](/docs/api/get-service-id-waf-zones-zone-events) | `waf:read` | | `GET` | `/v1/service/@id/waf/zones/@zone/hostnames` | [Tên miền của website](/docs/api/get-service-id-waf-zones-zone-hostnames) | `waf:read` | | `POST` | `/v1/service/@id/waf/zones/@zone/hostnames` | [Thêm tên miền vào website](/docs/api/post-service-id-waf-zones-zone-hostnames) | `waf:write` | | `DELETE` | `/v1/service/@id/waf/zones/@zone/hostnames/@hostname` | [Gỡ tên miền khỏi website](/docs/api/delete-service-id-waf-zones-zone-hostnames-hostname) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone/origin` | [Máy chủ gốc của website](/docs/api/get-service-id-waf-zones-zone-origin) | `waf:read` | | `PUT` | `/v1/service/@id/waf/zones/@zone/origin` | [Sửa máy chủ gốc](/docs/api/put-service-id-waf-zones-zone-origin) | `waf:write` | | `PUT` | `/v1/service/@id/waf/zones/@zone/under-attack` | [Bật, tắt chống tấn công khẩn cấp](/docs/api/put-service-id-waf-zones-zone-under-attack) | `waf:write` | | `PUT` | `/v1/service/@id/waf/zones/@zone/waf-mode` | [Đổi mức bảo vệ](/docs/api/put-service-id-waf-zones-zone-waf-mode) | `waf:write` | ## Ticket & hỗ trợ ### Ticket & hỗ trợ | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/knowledgebase` | [Danh mục bài hướng dẫn](/docs/api/get-knowledgebase) | `tickets:read` | | `GET` | `/v1/knowledgebase/@category_id` | [Bài hướng dẫn trong danh mục](/docs/api/get-knowledgebase-category-id) | `tickets:read` | | `GET` | `/v1/knowledgebase/article/@article_id` | [Chi tiết bài hướng dẫn](/docs/api/get-knowledgebase-article-article-id) | `tickets:read` | | `GET` | `/v1/news` | [Danh sách tin tức](/docs/api/get-news) | `tickets:read` | | `GET` | `/v1/news/@news_id` | [Chi tiết tin tức](/docs/api/get-news-news-id) | `tickets:read` | | `GET` | `/v1/ticket/attachment/@file` | [Tải tệp đính kèm ticket](/docs/api/get-ticket-attachment-file) | `tickets:read` | | `GET` | `/v1/ticket/departments` | [Phòng ban hỗ trợ](/docs/api/get-ticket-departments) | `tickets:read` | | `GET` | `/v1/tickets` | [Danh sách ticket](/docs/api/get-tickets) | `tickets:read` | | `POST` | `/v1/tickets` | [Tạo ticket](/docs/api/post-tickets) | `tickets:write` | | `GET` | `/v1/tickets/@number` | [Chi tiết ticket](/docs/api/get-tickets-number) | `tickets:read` | | `POST` | `/v1/tickets/@number` | [Trả lời ticket](/docs/api/post-tickets-number) | `tickets:write` | | `PUT` | `/v1/tickets/@number/close` | [Đóng ticket](/docs/api/put-tickets-number-close) | `tickets:write` | | `PUT` | `/v1/tickets/@number/open` | [Mở lại ticket](/docs/api/put-tickets-number-open) | `tickets:write` | --- # Identity & SSO Đăng nhập bằng Tino (OAuth 2.0, OpenID Connect), token API cá nhân, thông tin tài khoản. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hướng dẫn - [Đăng nhập bằng Tino (OAuth 2.0, OpenID Connect)](/docs/oauth) - [Token API cá nhân](/docs/personal-tokens) - [Đăng nhập từ CLI và ứng dụng không có backend](/docs/cli-login) ## Tài khoản | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/clientarea` | [Tổng quan tài khoản](/docs/api/get-clientarea) | `profile:read` | | `GET` | `/v1/clientarea/nav/service` | [Danh mục dịch vụ](/docs/api/get-clientarea-nav-service) | `profile:read` | | `POST` | `/v1/clientarea/search/@query` | [Tìm dịch vụ, sản phẩm](/docs/api/post-clientarea-search-query) | `profile:read` | | `GET` | `/v1/clientarea/statuses` | [Danh sách trạng thái](/docs/api/get-clientarea-statuses) | `profile:read` | | `GET` | `/v1/contact` | [Danh sách liên hệ](/docs/api/get-contact) | `profile:read` | | `GET` | `/v1/contact/@id` | [Chi tiết liên hệ](/docs/api/get-contact-id) | `profile:read` | | `GET` | `/v1/contact/privileges` | [Quyền có thể cấp cho liên hệ](/docs/api/get-contact-privileges) | `profile:read` | | `GET` | `/v1/contacts` | [Danh sách liên hệ (contacts)](/docs/api/get-contacts) | `profile:read` | | `GET` | `/v1/details` | [Thông tin tài khoản](/docs/api/get-details) | `profile:read` | | `GET` | `/v1/notifications` | [Danh sách thông báo](/docs/api/get-notifications) | `profile:read` | | `PUT` | `/v1/notifications/@id/ack` | [Đánh dấu đã đọc thông báo](/docs/api/put-notifications-id-ack) | `profile:write` | | `GET` | `/v1/notifications/new` | [Thông báo chưa đọc](/docs/api/get-notifications-new) | `profile:read` | --- # Domains & DNS Tra cứu, đặt mua, gia hạn tên miền; nameserver, DNSSEC; vùng và bản ghi DNS. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hướng dẫn - [Hồ sơ chủ thể tên miền](/docs/domain-registrant) ## Tên miền | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/domain` | [Danh sách tên miền](/docs/api/get-domain) | `domains:read` | | `GET` | `/v1/domain/@id` | [Chi tiết tên miền](/docs/api/get-domain-id) | `domains:read` | | `GET` | `/v1/domain/@id/autorenew` | [Xem tự gia hạn tên miền](/docs/api/get-domain-id-autorenew) | `domains:read` | | `PUT` | `/v1/domain/@id/autorenew` | [Bật/tắt tự gia hạn tên miền](/docs/api/put-domain-id-autorenew) | `domains:write` | | `GET` | `/v1/domain/@id/contact` | [Xem liên hệ tên miền](/docs/api/get-domain-id-contact) | `domains:read` | | `PUT` | `/v1/domain/@id/contact` | [Đổi liên hệ (chủ thể) tên miền](/docs/api/put-domain-id-contact) | `domains:owner` | | `GET` | `/v1/domain/@id/dnssec` | [Danh sách khoá DNSSEC](/docs/api/get-domain-id-dnssec) | `domains:read` | | `PUT` | `/v1/domain/@id/dnssec` | [Thêm khoá DNSSEC](/docs/api/put-domain-id-dnssec) | `domains:write` | | `DELETE` | `/v1/domain/@id/dnssec/@key` | [Xoá khoá DNSSEC](/docs/api/delete-domain-id-dnssec-key) | `domains:write` | | `GET` | `/v1/domain/@id/dnssec/flags` | [Tham số DNSSEC hỗ trợ](/docs/api/get-domain-id-dnssec-flags) | `domains:read` | | `GET` | `/v1/domain/@id/emforwarding` | [Xem chuyển tiếp email](/docs/api/get-domain-id-emforwarding) | `domains:read` | | `PUT` | `/v1/domain/@id/emforwarding` | [Cập nhật chuyển tiếp email](/docs/api/put-domain-id-emforwarding) | `domains:write` | | `GET` | `/v1/domain/@id/epp` | [Lấy mã chuyển tên miền (EPP)](/docs/api/get-domain-id-epp) | `domains:owner` | | `PUT` | `/v1/domain/@id/forwarding` | [Cập nhật chuyển hướng tên miền](/docs/api/put-domain-id-forwarding) | `domains:write` | | `PUT` | `/v1/domain/@id/idprotection` | [Bật/tắt ẩn thông tin chủ thể](/docs/api/put-domain-id-idprotection) | `domains:write` | | `GET` | `/v1/domain/@id/invoices` | [Hoá đơn của tên miền](/docs/api/get-domain-id-invoices) | `domains:read` | | `GET` | `/v1/domain/@id/ns` | [Xem nameserver](/docs/api/get-domain-id-ns) | `domains:read` | | `PUT` | `/v1/domain/@id/ns` | [Đổi nameserver](/docs/api/put-domain-id-ns) | `domains:write` | | `GET` | `/v1/domain/@id/reg` | [Nameserver riêng đã đăng ký](/docs/api/get-domain-id-reg) | `domains:read` | | `POST` | `/v1/domain/@id/reg` | [Quản lý nameserver riêng](/docs/api/post-domain-id-reg) | `domains:write` | | `GET` | `/v1/domain/@id/reglock` | [Xem khoá tên miền](/docs/api/get-domain-id-reglock) | `domains:read` | | `PUT` | `/v1/domain/@id/reglock` | [Bật/tắt khoá tên miền](/docs/api/put-domain-id-reglock) | `domains:write` | | `POST` | `/v1/domain/@id/renew` | [Gia hạn tên miền](/docs/api/post-domain-id-renew) | `domains:write` | | `GET` | `/v1/domain/@id/sync` | [Đồng bộ tên miền](/docs/api/get-domain-id-sync) | `domains:write` | | `POST` | `/v1/domain/lookup` | [Kiểm tra tên miền còn trống](/docs/api/post-domain-lookup) | `domains:read` | | `GET` | `/v1/domain/name/@name` | [Chi tiết tên miền theo tên](/docs/api/get-domain-name-name) | `domains:read` | | `GET` | `/v1/domain/order` | [Đuôi tên miền có thể đăng ký](/docs/api/get-domain-order) | `domains:read` | | `POST` | `/v1/domain/order` | [Đặt mua tên miền](/docs/api/post-domain-order) | `domains:write` | | `GET` | `/v1/domain/order/@id/form` | [Thông tin bổ sung theo đuôi tên miền](/docs/api/get-domain-order-id-form) | `domains:read` | | `GET` | `/v1/domains` | [Danh sách tên miền (phân trang)](/docs/api/get-domains) | `domains:read` | | `GET` | `/v1/domains/@id/registrant` | [Xem chủ thể tên miền đang chờ](/docs/api/get-domains-id-registrant) | `domains:registrant` | | `PUT` | `/v1/domains/@id/registrant` | [Lưu chủ thể tên miền đang chờ](/docs/api/put-domains-id-registrant) | `domains:registrant` | | `GET` | `/v1/domains/pending` | [Tên miền chờ hoàn tất hồ sơ](/docs/api/get-domains-pending) | `domains:registrant` | | `GET` | `/v1/registrants` | [Chủ thể đã dùng](/docs/api/get-registrants) | `domains:registrant` | | `GET` | `/v1/whois/@domain` | [Tra whois tên miền (bằng token)](/docs/api/get-v1-whois-domain) | `domains:read` | | `GET` | `/whois/@domain` | [Tra whois tên miền](/docs/api/get-whois-domain) | — | ## DNS | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/dns` | [Danh sách vùng DNS](/docs/api/get-dns) | `dns:read` | | `GET` | `/v1/dns/templates` | [Mẫu bản ghi DNS](/docs/api/get-dns-templates) | `dns:read` | | `GET` | `/v1/domain/@id/dns` | [Bản ghi DNS của tên miền](/docs/api/get-domain-id-dns) | `dns:read` | | `POST` | `/v1/domain/@id/dns` | [Thêm bản ghi DNS cho tên miền](/docs/api/post-domain-id-dns) | `dns:write` | | `PUT` | `/v1/domain/@id/dns/@index` | [Sửa bản ghi DNS của tên miền](/docs/api/put-domain-id-dns-index) | `dns:write` | | `DELETE` | `/v1/domain/@id/dns/@index` | [Xoá bản ghi DNS của tên miền](/docs/api/delete-domain-id-dns-index) | `dns:write` | | `GET` | `/v1/domain/@id/dns/types` | [Loại bản ghi DNS hỗ trợ](/docs/api/get-domain-id-dns-types) | `dns:read` | | `GET` | `/v1/service/@service_id/dns` | [Vùng DNS của dịch vụ](/docs/api/get-service-service-id-dns) | `dns:read` | | `POST` | `/v1/service/@service_id/dns` | [Thêm vùng DNS](/docs/api/post-service-service-id-dns) | `dns:write` | | `GET` | `/v1/service/@service_id/dns/@zone_id` | [Chi tiết vùng DNS](/docs/api/get-service-service-id-dns-zone-id) | `dns:read` | | `PUT` | `/v1/service/@service_id/dns/@zone_id` | [Sửa vùng DNS](/docs/api/put-service-service-id-dns-zone-id) | `dns:write` | | `DELETE` | `/v1/service/@service_id/dns/@zone_id` | [Xoá vùng DNS](/docs/api/delete-service-service-id-dns-zone-id) | `dns:write` | | `GET` | `/v1/service/@service_id/dns/@zone_id/dnssec` | [Xem DNSSEC của vùng DNS](/docs/api/get-service-service-id-dns-zone-id-dnssec) | `dns:read` | | `PUT` | `/v1/service/@service_id/dns/@zone_id/dnssec` | [Bật/tắt DNSSEC của vùng DNS](/docs/api/put-service-service-id-dns-zone-id-dnssec) | `dns:write` | | `POST` | `/v1/service/@service_id/dns/@zone_id/records` | [Thêm bản ghi DNS](/docs/api/post-service-service-id-dns-zone-id-records) | `dns:write` | | `PUT` | `/v1/service/@service_id/dns/@zone_id/records/@record_id` | [Sửa bản ghi DNS](/docs/api/put-service-service-id-dns-zone-id-records-record-id) | `dns:write` | | `DELETE` | `/v1/service/@service_id/dns/@zone_id/records/@record_id` | [Xoá bản ghi DNS](/docs/api/delete-service-service-id-dns-zone-id-records-record-id) | `dns:write` | --- # Cloud & Hosting Dịch vụ hosting, máy chủ VPS (bật, tắt, mạng, IP), chứng chỉ SSL. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Dịch vụ | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service` | [Danh sách dịch vụ](/docs/api/get-service) | `services:read` | | `GET` | `/v1/service/@id` | [Chi tiết dịch vụ](/docs/api/get-service-id) | `services:read` | | `POST` | `/v1/service/@id/cancel` | [Yêu cầu huỷ dịch vụ](/docs/api/post-service-id-cancel) | `services:write` | | `GET` | `/v1/service/@id/cycle` | [Các chu kỳ thanh toán](/docs/api/get-service-id-cycle) | `services:read` | | `POST` | `/v1/service/@id/cycle` | [Đổi chu kỳ thanh toán](/docs/api/post-service-id-cycle) | `services:write` | | `GET` | `/v1/service/@id/emails` | [Tài khoản email của hosting](/docs/api/get-service-id-emails) | `services:read` | | `GET` | `/v1/service/@id/invoices` | [Hoá đơn của dịch vụ](/docs/api/get-service-id-invoices) | `services:read` | | `GET` | `/v1/service/@id/label` | [Xem nhãn dịch vụ](/docs/api/get-service-id-label) | `services:read` | | `POST` | `/v1/service/@id/label` | [Đặt nhãn dịch vụ](/docs/api/post-service-id-label) | `services:write` | | `POST` | `/v1/service/@id/manualrenew` | [Tạo hoá đơn gia hạn dịch vụ](/docs/api/post-service-id-manualrenew) | `services:write` | | `GET` | `/v1/service/@id/methods` | [Thao tác hỗ trợ của dịch vụ](/docs/api/get-service-id-methods) | `services:read` | | `POST` | `/v1/service/@id/renew` | [Gia hạn dịch vụ](/docs/api/post-service-id-renew) | `services:write` | | `GET` | `/v1/service/@id/upgrade` | [Tuỳ chọn nâng cấp](/docs/api/get-service-id-upgrade) | `services:read` | | `POST` | `/v1/service/@id/upgrade` | [Báo giá hoặc yêu cầu nâng cấp](/docs/api/post-service-id-upgrade) | `services:write` | | `GET` | `/v1/service/@id/widgets` | [Tiện ích của dịch vụ](/docs/api/get-service-id-widgets) | `services:read` | | `GET` | `/v1/service/cpanel2/@id/statistics` | [Thống kê cPanel](/docs/api/get-service-cpanel2-id-statistics) | `services:read` | | `POST` | `/v1/service/cpanel2/@id/unblock` | [Gỡ chặn IP trên cPanel](/docs/api/post-service-cpanel2-id-unblock) | `services:write` | | `GET` | `/v1/services/@cid` | [Dịch vụ theo danh mục](/docs/api/get-services-cid) | `services:read` | | `GET` | `/v1/services/active` | [Dịch vụ đang hoạt động](/docs/api/get-services-active) | `services:read` | ## Máy chủ VPS | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service/@id/networks` | [Mạng và dải IP](/docs/api/get-service-id-networks) | `services:read` | | `GET` | `/v1/service/@id/resources` | [Tài nguyên VPS](/docs/api/get-service-id-resources) | `services:read` | | `GET` | `/v1/service/@id/templates` | [Mẫu hệ điều hành](/docs/api/get-service-id-templates) | `services:read` | | `GET` | `/v1/service/@id/vms` | [Danh sách máy ảo](/docs/api/get-service-id-vms) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid` | [Chi tiết máy ảo](/docs/api/get-service-id-vms-vmid) | `services:read` | | `POST` | `/v1/service/@id/vms/@vmid/hostname` | [Đổi hostname máy ảo](/docs/api/post-service-id-vms-vmid-hostname) | `services:write` | | `GET` | `/v1/service/@id/vms/@vmid/interfaces` | [Card mạng của máy ảo](/docs/api/get-service-id-vms-vmid-interfaces) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/interfaces/@iface` | [Chi tiết card mạng](/docs/api/get-service-id-vms-vmid-interfaces-iface) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/ippool` | [Dải IP của máy ảo](/docs/api/get-service-id-vms-vmid-ippool) | `services:read` | | `GET` | `/v1/service/@id/vms/@vmid/ips` | [IP của máy ảo](/docs/api/get-service-id-vms-vmid-ips) | `services:read` | | `POST` | `/v1/service/@id/vms/@vmid/reboot` | [Khởi động lại máy ảo](/docs/api/post-service-id-vms-vmid-reboot) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/reset` | [Reset máy ảo](/docs/api/post-service-id-vms-vmid-reset) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/shutdown` | [Tắt máy ảo](/docs/api/post-service-id-vms-vmid-shutdown) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/start` | [Bật máy ảo](/docs/api/post-service-id-vms-vmid-start) | `services:write` | | `POST` | `/v1/service/@id/vms/@vmid/stop` | [Dừng máy ảo](/docs/api/post-service-id-vms-vmid-stop) | `services:write` | | `GET` | `/v1/service/@id/vms/@vmid/traffic` | [Lưu lượng mạng của máy ảo](/docs/api/get-service-id-vms-vmid-traffic) | `services:read` | ## Chứng chỉ SSL | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/certificate` | [Danh sách chứng chỉ SSL](/docs/api/get-certificate) | `services:read` | | `GET` | `/v1/certificate/@id` | [Chi tiết chứng chỉ SSL](/docs/api/get-certificate-id) | `services:read` | | `GET` | `/v1/certificate/@id/crt` | [Tải chứng chỉ](/docs/api/get-certificate-id-crt) | `services:read` | | `GET` | `/v1/certificate/order` | [Chứng chỉ có thể mua](/docs/api/get-certificate-order) | `services:read` | | `POST` | `/v1/certificate/order` | [Đặt mua chứng chỉ SSL](/docs/api/post-certificate-order) | `services:write` | | `GET` | `/v1/certificate/order/@product_id/software` | [Phần mềm máy chủ cho chứng chỉ](/docs/api/get-certificate-order-product-id-software) | `services:read` | | `GET` | `/v1/certificates` | [Danh sách dịch vụ SSL (certificates)](/docs/api/get-certificates) | `services:read` | --- # Billing Hoá đơn, báo giá, số dư, nạp tiền và thanh toán. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hoá đơn & thanh toán | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/addfunds` | [Thông tin nạp tiền](/docs/api/get-addfunds) | `billing:read` | | `POST` | `/v1/addfunds` | [Nạp tiền](/docs/api/post-addfunds) | `billing:write` | | `GET` | `/v1/balance` | [Số dư tài khoản](/docs/api/get-balance) | `billing:read` | | `GET` | `/v1/billing/@invoice_id/pay/@gateway_id` | [Link thanh toán hoá đơn](/docs/api/get-billing-invoice-id-pay-gateway-id) | `billing:write` | | `POST` | `/v1/billing/addfunds` | [Nạp tiền (billing)](/docs/api/post-billing-addfunds) | `billing:write` | | `GET` | `/v1/billing/creditlogs` | [Lịch sử số dư tín dụng](/docs/api/get-billing-creditlogs) | `billing:read` | | `POST` | `/v1/billing/creditvoucher` | [Dùng mã nạp tiền](/docs/api/post-billing-creditvoucher) | `billing:write` | | `GET` | `/v1/estimate/@id/pdf` | [Tải PDF báo giá](/docs/api/get-estimate-id-pdf) | `billing:read` | | `GET` | `/v1/estimates` | [Danh sách báo giá](/docs/api/get-estimates) | `billing:read` | | `GET` | `/v1/estimates/@id` | [Chi tiết báo giá](/docs/api/get-estimates-id) | `billing:read` | | `GET` | `/v1/invoice` | [Danh sách hoá đơn](/docs/api/get-invoice) | `billing:read` | | `GET` | `/v1/invoice/@id` | [Chi tiết hoá đơn](/docs/api/get-invoice-id) | `billing:read` | | `DELETE` | `/v1/invoice/@id` | [Xoá hoá đơn](/docs/api/delete-invoice-id) | `billing:write` | | `POST` | `/v1/invoice/@id/credit` | [Trả hoá đơn bằng số dư](/docs/api/post-invoice-id-credit) | `billing:write` | | `GET` | `/v1/invoice/@id/pdf` | [Tải PDF hoá đơn](/docs/api/get-invoice-id-pdf) | `billing:read` | | `GET` | `/v1/invoices` | [Danh sách hoá đơn (phân trang)](/docs/api/get-invoices) | `billing:read` | | `GET` | `/v1/invoices/due` | [Hoá đơn đến hạn](/docs/api/get-invoices-due) | `billing:read` | | `POST` | `/v1/invoices/payall` | [Thanh toán gộp hoá đơn](/docs/api/post-invoices-payall) | `billing:write` | | `GET` | `/v1/payment` | [Phương thức thanh toán](/docs/api/get-payment) | `billing:read` | | `GET` | `/v1/payment/fees` | [Phí phương thức thanh toán](/docs/api/get-payment-fees) | `billing:read` | ## Đặt hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/v1/carts` | [Tạo giỏ hàng](/docs/api/post-carts) | `orders:write` | | `GET` | `/v1/carts/@uuid` | [Xem giỏ hàng](/docs/api/get-carts-uuid) | `orders:write` | | `PUT` | `/v1/carts/@uuid` | [Sửa giỏ hàng](/docs/api/put-carts-uuid) | `orders:write` | | `POST` | `/v1/carts/@uuid/confirm` | [Chốt đơn từ giỏ](/docs/api/post-carts-uuid-confirm) | `orders:write` | | `GET` | `/v1/carts/latest` | [Giỏ hàng gần nhất](/docs/api/get-carts-latest) | `orders:write` | | `POST` | `/v1/order` | [Đặt mua nhiều dịch vụ](/docs/api/post-order) | `orders:write` | | `POST` | `/v1/order/@product_id` | [Đặt mua một dịch vụ](/docs/api/post-order-product-id) | `orders:write` | | `POST` | `/v1/quote` | [Báo giá đơn hàng](/docs/api/post-quote) | `orders:write` | --- # TinoPay Nhận chuyển khoản qua tài khoản ngân hàng liên kết và tài khoản ảo (VA); webhook, thông báo Telegram, Zalo, Lark cho từng giao dịch; API token. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hướng dẫn - [Bắt đầu với TinoPay](/docs/tinopay-start) - [Nhận webhook TinoPay](/docs/tinopay-webhook) - [Thông báo Telegram, Zalo, Lark](/docs/tinopay-notifications) - [API công khai TinoPay](/docs/tinopay-api) - [Tích hợp không cần code](/docs/tinopay-integrations) ## Merchant | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay` | [Thông tin merchant](/docs/api/tinopay-get-merchant) | — | | `PATCH` | `/service/@id/tinopay` | [Sửa thông tin merchant](/docs/api/tinopay-patch-merchant) | — | | `GET` | `/service/@id/tinopay/pay-codes` | [Cấu trúc mã thanh toán](/docs/api/tinopay-get-pay-codes) | — | | `PUT` | `/service/@id/tinopay/pay-codes` | [Lưu cấu trúc mã thanh toán](/docs/api/tinopay-put-pay-codes) | — | ## Tài khoản ngân hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/bank-accounts` | [Danh sách tài khoản ngân hàng](/docs/api/tinopay-get-bank-accounts) | — | | `GET` | `/service/@id/tinopay/bank-accounts/@bank` | [Chi tiết tài khoản ngân hàng](/docs/api/tinopay-get-bank-accounts-bank) | — | | `POST` | `/service/@id/tinopay/bank-links/bidv-business` | [Yêu cầu liên kết BIDV doanh nghiệp](/docs/api/tinopay-post-bank-links-bidv-business) | — | ## Tài khoản ảo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts` | [Danh sách tài khoản ảo (VA)](/docs/api/tinopay-get-bank-accounts-bank-virtual-accounts) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts` | [Tạo tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va/activate` | [Mở tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts-va-activate) | — | | `POST` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va/deactivate` | [Khoá tài khoản ảo](/docs/api/tinopay-post-bank-accounts-bank-virtual-accounts-va-deactivate) | — | | `DELETE` | `/service/@id/tinopay/bank-accounts/@bank/virtual-accounts/@va` | [Xoá tài khoản ảo](/docs/api/tinopay-delete-bank-accounts-bank-virtual-accounts-va) | — | ## Webhook | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/webhooks` | [Danh sách webhook](/docs/api/tinopay-get-webhooks) | — | | `POST` | `/service/@id/tinopay/webhooks` | [Tạo webhook](/docs/api/tinopay-post-webhooks) | — | | `GET` | `/service/@id/tinopay/webhooks/@webhook` | [Chi tiết webhook](/docs/api/tinopay-get-webhooks-webhook) | — | | `PATCH` | `/service/@id/tinopay/webhooks/@webhook` | [Sửa webhook](/docs/api/tinopay-patch-webhooks-webhook) | — | | `DELETE` | `/service/@id/tinopay/webhooks/@webhook` | [Xoá webhook](/docs/api/tinopay-delete-webhooks-webhook) | — | | `GET` | `/service/@id/tinopay/webhook-logs` | [Log webhook](/docs/api/tinopay-get-webhook-logs) | — | | `POST` | `/service/@id/tinopay/webhook-logs/@log/resend` | [Gửi lại log webhook](/docs/api/tinopay-post-webhook-logs-log-resend) | — | ## Giao dịch | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/transactions` | [Lịch sử giao dịch](/docs/api/tinopay-get-transactions) | — | | `GET` | `/service/@id/tinopay/transactions/summary` | [Tổng hợp giao dịch](/docs/api/tinopay-get-transactions-summary) | — | | `GET` | `/service/@id/tinopay/transactions/@transaction` | [Chi tiết giao dịch](/docs/api/tinopay-get-transactions-transaction) | — | | `POST` | `/service/@id/tinopay/transactions/@transaction/resend-webhook` | [Bắn lại webhook cho giao dịch](/docs/api/tinopay-post-transactions-transaction-resend-webhook) | — | ## Thông báo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/service/@id/tinopay/notification-apps/bot-info` | [Kiểm token bot](/docs/api/tinopay-post-notification-apps-bot-info) | — | | `POST` | `/service/@id/tinopay/notification-apps/find-chats` | [Tìm nơi nhận của bot](/docs/api/tinopay-post-notification-apps-find-chats) | — | | `POST` | `/service/@id/tinopay/notification-apps/test` | [Gửi tin thử](/docs/api/tinopay-post-notification-apps-test) | — | | `GET` | `/service/@id/tinopay/notification-apps` | [Danh sách ứng dụng thông báo](/docs/api/tinopay-get-notification-apps) | — | | `POST` | `/service/@id/tinopay/notification-apps` | [Tạo ứng dụng thông báo](/docs/api/tinopay-post-notification-apps) | — | | `GET` | `/service/@id/tinopay/notification-apps/@app` | [Chi tiết ứng dụng thông báo](/docs/api/tinopay-get-notification-apps-app) | — | | `PATCH` | `/service/@id/tinopay/notification-apps/@app` | [Sửa ứng dụng thông báo](/docs/api/tinopay-patch-notification-apps-app) | — | | `DELETE` | `/service/@id/tinopay/notification-apps/@app` | [Xoá ứng dụng thông báo](/docs/api/tinopay-delete-notification-apps-app) | — | ## Tích hợp Sapo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `POST` | `/service/@id/tinopay/sapo-integrations/test` | [Thử kết nối Sapo](/docs/api/tinopay-post-sapo-integrations-test) | — | | `GET` | `/service/@id/tinopay/sapo-integrations` | [Danh sách tích hợp Sapo](/docs/api/tinopay-get-sapo-integrations) | — | | `POST` | `/service/@id/tinopay/sapo-integrations` | [Tạo tích hợp Sapo](/docs/api/tinopay-post-sapo-integrations) | — | | `GET` | `/service/@id/tinopay/sapo-integrations/@integration` | [Chi tiết tích hợp Sapo](/docs/api/tinopay-get-sapo-integrations-integration) | — | | `PATCH` | `/service/@id/tinopay/sapo-integrations/@integration` | [Sửa tích hợp Sapo](/docs/api/tinopay-patch-sapo-integrations-integration) | — | | `DELETE` | `/service/@id/tinopay/sapo-integrations/@integration` | [Xoá tích hợp Sapo](/docs/api/tinopay-delete-sapo-integrations-integration) | — | | `GET` | `/service/@id/tinopay/sapo-order-logs` | [Nhật ký đối soát Sapo](/docs/api/tinopay-get-sapo-order-logs) | — | ## API token | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/tinopay/api-tokens` | [Danh sách API token](/docs/api/tinopay-get-api-tokens) | — | | `POST` | `/service/@id/tinopay/api-tokens` | [Tạo API token](/docs/api/tinopay-post-api-tokens) | — | | `DELETE` | `/service/@id/tinopay/api-tokens/@token` | [Thu hồi API token](/docs/api/tinopay-delete-api-tokens-token) | — | --- # Tino Uptime Theo dõi website, máy chủ, cổng, DNS, SSL và tên miền; uptime, sự cố, cảnh báo qua email, Telegram, Discord, Slack, webhook, Zalo. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hướng dẫn - [Bắt đầu với Tino Uptime](/docs/uptime-start) ## Gói Uptime | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime` | [Tổng quan gói Tino Uptime](/docs/api/uptime-get-overview) | — | | `GET` | `/service/@id/uptime/usage` | [Mức dùng so với hạn mức](/docs/api/uptime-get-usage) | — | ## Monitor | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/monitors` | [Danh sách monitor](/docs/api/uptime-get-monitors) | — | | `POST` | `/service/@id/uptime/monitors` | [Tạo monitor](/docs/api/uptime-post-monitors) | — | | `GET` | `/service/@id/uptime/monitors/@monitor` | [Chi tiết monitor](/docs/api/uptime-get-monitors-monitor) | — | | `PUT` | `/service/@id/uptime/monitors/@monitor` | [Sửa monitor](/docs/api/uptime-put-monitors-monitor) | — | | `DELETE` | `/service/@id/uptime/monitors/@monitor` | [Xoá monitor](/docs/api/uptime-delete-monitors-monitor) | — | | `POST` | `/service/@id/uptime/monitors/@monitor/pause` | [Tạm dừng monitor](/docs/api/uptime-post-monitors-monitor-pause) | — | | `POST` | `/service/@id/uptime/monitors/@monitor/resume` | [Chạy lại monitor](/docs/api/uptime-post-monitors-monitor-resume) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/uptime` | [Uptime của monitor](/docs/api/uptime-get-monitors-monitor-uptime) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/results` | [Kết quả kiểm của monitor](/docs/api/uptime-get-monitors-monitor-results) | — | | `GET` | `/service/@id/uptime/monitors/@monitor/incidents` | [Sự cố của monitor](/docs/api/uptime-get-monitors-monitor-incidents) | — | ## Sự cố | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/incidents` | [Danh sách sự cố](/docs/api/uptime-get-incidents) | — | | `GET` | `/service/@id/uptime/incidents/@incident` | [Chi tiết sự cố](/docs/api/uptime-get-incidents-incident) | — | | `POST` | `/service/@id/uptime/incidents/@incident/ack` | [Xác nhận sự cố](/docs/api/uptime-post-incidents-incident-ack) | — | ## Kênh cảnh báo | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/uptime/channels` | [Danh sách kênh cảnh báo](/docs/api/uptime-get-channels) | — | | `POST` | `/service/@id/uptime/channels` | [Tạo kênh cảnh báo](/docs/api/uptime-post-channels) | — | | `POST` | `/service/@id/uptime/channels/@channel/verify` | [Xác minh kênh cảnh báo](/docs/api/uptime-post-channels-channel-verify) | — | | `POST` | `/service/@id/uptime/channels/@channel/test` | [Gửi tin thử](/docs/api/uptime-post-channels-channel-test) | — | | `DELETE` | `/service/@id/uptime/channels/@channel` | [Xoá kênh cảnh báo](/docs/api/uptime-delete-channels-channel) | — | --- # TinoPage Builder Website dựng bằng AI: hạn mức theo dịch vụ, tạo website bằng AI, đăng, tạm ngưng, xoá, tên miền riêng, liên hệ và đơn hàng, đăng nhập một lần. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Hướng dẫn - [Bắt đầu với TinoPage Builder](/docs/builder-start) ## Tài khoản Builder | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/overview` | [Tổng quan tài khoản TinoPage Builder](/docs/api/builder-get-overview) | — | | `POST` | `/service/@id/builder/login` | [Vé đăng nhập một lần](/docs/api/builder-post-login) | — | ## Website | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites` | [Danh sách website](/docs/api/builder-get-sites) | — | | `GET` | `/service/@id/builder/sites/@site` | [Chi tiết website](/docs/api/builder-get-sites-site) | — | | `POST` | `/service/@id/builder/sites` | [Tạo website bằng AI](/docs/api/builder-post-sites) | — | | `GET` | `/service/@id/builder/site-creation` | [Tiến độ tạo website](/docs/api/builder-get-site-creation) | — | | `POST` | `/service/@id/builder/sites/@site/publish` | [Đăng website](/docs/api/builder-post-sites-site-publish) | — | | `POST` | `/service/@id/builder/sites/@site/unpublish` | [Tạm ngưng website](/docs/api/builder-post-sites-site-unpublish) | — | | `DELETE` | `/service/@id/builder/sites/@site` | [Xoá website](/docs/api/builder-delete-sites-site) | — | ## Tên miền riêng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites/@site/domains` | [Tên miền riêng của website](/docs/api/builder-get-sites-site-domains) | — | | `POST` | `/service/@id/builder/sites/@site/domains` | [Gắn tên miền riêng](/docs/api/builder-post-sites-site-domains) | — | | `POST` | `/service/@id/builder/sites/@site/domains/@hostname/verify` | [Kiểm tra lại DNS](/docs/api/builder-post-sites-site-domains-hostname-verify) | — | | `DELETE` | `/service/@id/builder/sites/@site/domains/@hostname` | [Gỡ tên miền riêng](/docs/api/builder-delete-sites-site-domains-hostname) | — | ## Liên hệ & đơn hàng | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/service/@id/builder/sites/@site/leads` | [Liên hệ và đơn hàng](/docs/api/builder-get-sites-site-leads) | — | --- # TinoWAF Tường lửa website: thêm website, mức bảo vệ, chống tấn công khẩn cấp, tên miền và bản ghi DNS, máy chủ gốc, nhật ký sự kiện, chặn hoặc cho phép IP. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## TinoWAF | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/service/@id/waf/events` | [Tóm tắt sự kiện](/docs/api/get-service-id-waf-events) | `waf:read` | | `GET` | `/v1/service/@id/waf/ip-rules` | [Danh sách IP chặn, cho phép](/docs/api/get-service-id-waf-ip-rules) | `waf:read` | | `POST` | `/v1/service/@id/waf/ip-rules` | [Chặn hoặc cho phép IP](/docs/api/post-service-id-waf-ip-rules) | `waf:write` | | `DELETE` | `/v1/service/@id/waf/ip-rules/@rule` | [Xoá mục IP](/docs/api/delete-service-id-waf-ip-rules-rule) | `waf:write` | | `POST` | `/v1/service/@id/waf/ip-rules/apply` | [Áp lại luật IP](/docs/api/post-service-id-waf-ip-rules-apply) | `waf:write` | | `GET` | `/v1/service/@id/waf/overview` | [Tổng quan TinoWAF](/docs/api/get-service-id-waf-overview) | `waf:read` | | `GET` | `/v1/service/@id/waf/zones` | [Danh sách website](/docs/api/get-service-id-waf-zones) | `waf:read` | | `POST` | `/v1/service/@id/waf/zones` | [Thêm website](/docs/api/post-service-id-waf-zones) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone` | [Chi tiết website](/docs/api/get-service-id-waf-zones-zone) | `waf:read` | | `DELETE` | `/v1/service/@id/waf/zones/@zone` | [Xoá website](/docs/api/delete-service-id-waf-zones-zone) | `waf:write` | | `POST` | `/v1/service/@id/waf/zones/@zone/check` | [Kiểm tra DNS ngay](/docs/api/post-service-id-waf-zones-zone-check) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone/events` | [Nhật ký sự kiện của website](/docs/api/get-service-id-waf-zones-zone-events) | `waf:read` | | `GET` | `/v1/service/@id/waf/zones/@zone/hostnames` | [Tên miền của website](/docs/api/get-service-id-waf-zones-zone-hostnames) | `waf:read` | | `POST` | `/v1/service/@id/waf/zones/@zone/hostnames` | [Thêm tên miền vào website](/docs/api/post-service-id-waf-zones-zone-hostnames) | `waf:write` | | `DELETE` | `/v1/service/@id/waf/zones/@zone/hostnames/@hostname` | [Gỡ tên miền khỏi website](/docs/api/delete-service-id-waf-zones-zone-hostnames-hostname) | `waf:write` | | `GET` | `/v1/service/@id/waf/zones/@zone/origin` | [Máy chủ gốc của website](/docs/api/get-service-id-waf-zones-zone-origin) | `waf:read` | | `PUT` | `/v1/service/@id/waf/zones/@zone/origin` | [Sửa máy chủ gốc](/docs/api/put-service-id-waf-zones-zone-origin) | `waf:write` | | `PUT` | `/v1/service/@id/waf/zones/@zone/under-attack` | [Bật, tắt chống tấn công khẩn cấp](/docs/api/put-service-id-waf-zones-zone-under-attack) | `waf:write` | | `PUT` | `/v1/service/@id/waf/zones/@zone/waf-mode` | [Đổi mức bảo vệ](/docs/api/put-service-id-waf-zones-zone-waf-mode) | `waf:write` | --- # Ticket & hỗ trợ Ticket, phòng ban, thư viện hướng dẫn và tin tức. Mọi route gọi qua gateway `https://api.tino.vn/v1` với `Authorization: Bearer `; xem [Gọi API Tino](/docs/api). ## Ticket & hỗ trợ | Method | Đường dẫn | Tên | Quyền | | --- | --- | --- | --- | | `GET` | `/v1/knowledgebase` | [Danh mục bài hướng dẫn](/docs/api/get-knowledgebase) | `tickets:read` | | `GET` | `/v1/knowledgebase/@category_id` | [Bài hướng dẫn trong danh mục](/docs/api/get-knowledgebase-category-id) | `tickets:read` | | `GET` | `/v1/knowledgebase/article/@article_id` | [Chi tiết bài hướng dẫn](/docs/api/get-knowledgebase-article-article-id) | `tickets:read` | | `GET` | `/v1/news` | [Danh sách tin tức](/docs/api/get-news) | `tickets:read` | | `GET` | `/v1/news/@news_id` | [Chi tiết tin tức](/docs/api/get-news-news-id) | `tickets:read` | | `GET` | `/v1/ticket/attachment/@file` | [Tải tệp đính kèm ticket](/docs/api/get-ticket-attachment-file) | `tickets:read` | | `GET` | `/v1/ticket/departments` | [Phòng ban hỗ trợ](/docs/api/get-ticket-departments) | `tickets:read` | | `GET` | `/v1/tickets` | [Danh sách ticket](/docs/api/get-tickets) | `tickets:read` | | `POST` | `/v1/tickets` | [Tạo ticket](/docs/api/post-tickets) | `tickets:write` | | `GET` | `/v1/tickets/@number` | [Chi tiết ticket](/docs/api/get-tickets-number) | `tickets:read` | | `POST` | `/v1/tickets/@number` | [Trả lời ticket](/docs/api/post-tickets-number) | `tickets:write` | | `PUT` | `/v1/tickets/@number/close` | [Đóng ticket](/docs/api/put-tickets-number-close) | `tickets:write` | | `PUT` | `/v1/tickets/@number/open` | [Mở lại ticket](/docs/api/put-tickets-number-open) | `tickets:write` | --- # Tổng quan tài khoản `GET /v1/clientarea` · quyền `profile:read` Số hoá đơn, tên miền, ticket và dịch vụ của tài khoản. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/clientarea` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số Route này không có tham số. ## Example request ```bash curl "https://api.tino.vn/v1/clientarea" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.get_summary()`, Node.js `await client.account.getSummary();`, PHP `$client->account->getSummary();`. ## Example response ```json { "total": { "invoices": 1, "domains": 1, "tickets": 3, "services": 3 } } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Danh mục dịch vụ `GET /v1/clientarea/nav/service` · quyền `profile:read` Danh mục và danh mục con của các loại dịch vụ, dùng dựng menu dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/clientarea/nav/service` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số Route này không có tham số. ## Example request ```bash curl "https://api.tino.vn/v1/clientarea/nav/service" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.get_service_nav()`, Node.js `await client.account.getServiceNav();`, PHP `$client->account->getServiceNav();`. ## Example response ```json { "categories": [ { "id": 84, "name": "Cloud Instance", "description": "", "slug": "cloud-instance", "subcategories": [ { "id": 93, "name": "Hermes Agent", "description": "", "slug": "hermes-agent" }, { "id": 70, "name": "NVMe VPS ", "description": "", "slug": "nvme-vps" }, "… 3 more item(s)" ] }, { "id": 54, "name": "Web Hosting", "description": "", "slug": "web-hosting", "subcategories": [ { "id": 74, "name": "Hosting NVMe", "description": "

Trải nghiệm tốc độ siêu nhanh với ổ cứng NVMe Enterprise chuẩn U.2 với giá tốt nhất. Phần cứng máy chủ cao cấp và mạnh mẽ với vi xử lý Intel Xeon Scalable Gen 2, máy chủ Dell chuyên dụng cho mọi nhà.

", "slug": "hosting-nvme" }, { "id": 53, "name": "Business Hosting", "description": "\n

Trải nghiệm tốc độ siêu nhanh với ổ cứng NVMe Enterprise chuẩn U.2 với giá tốt nhất. Phần cứng máy chủ cao cấp và mạnh mẽ với vi xử lý Intel Xeon Scalable Gen 2, máy chủ Dell chuyên dụng dành cho doanh nghiệp.

\n", "slug": "business-hosting" }, "… 4 more item(s)" ] }, "… 7 more item(s)" … 2 more line(s) ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Tìm dịch vụ, sản phẩm `POST /v1/clientarea/search/@query` · quyền `profile:read` Tìm trong dịch vụ và sản phẩm của tài khoản theo chuỗi `@query` (ví dụ một tên miền). Chỉ đọc, dù là `POST`. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/clientarea/search/@query` | | Method | `POST` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `query` | đường dẫn | string | có | Chuỗi cần tìm | ## Example request ```bash curl -X POST "https://api.tino.vn/v1/clientarea/search/example.com" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): chưa có hàm riêng, dùng `client.request("POST", "/clientarea/search/@query")`. ## Example response Chưa có mẫu thật: route thay đổi dữ liệu thật hoặc tài khoản thử không có dữ liệu cho route này. Câu trả lời là một đối tượng JSON; lỗi theo dạng chung ở [Gọi API Tino](/docs/api#loi). --- # Danh sách trạng thái `GET /v1/clientarea/statuses` · quyền `profile:read` Các giá trị trạng thái của hoá đơn, tên miền, ticket, dịch vụ và báo giá. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/clientarea/statuses` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số Route này không có tham số. ## Example request ```bash curl "https://api.tino.vn/v1/clientarea/statuses" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.list_statuses()`, Node.js `await client.account.listStatuses();`, PHP `$client->account->listStatuses();`. ## Example response ```json { "invoice": [ "Paid", "Unpaid", "… 4 more item(s)" ], "domain": [ "Pending", "Active", "… 4 more item(s)" ], "ticket": [ "Open", "Closed", "… 4 more item(s)" ], "service": [ "Pending", "Active", "… 4 more item(s)" ], "estimates": [ "Draft", "Sent", "… 3 more item(s)" ] } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Danh sách liên hệ `GET /v1/contact` · quyền `profile:read` Các liên hệ (tài khoản phụ) của tài khoản. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/contact` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `page` | query | integer | không | Zero-based page index. page=0 is the first page; the response echoes it 1-based in page.current. Default: `0`. | | `perpage` | query | integer | không | Rows per page. Defaults to the account's RecordsPerPage setting. | | `orderby` | query | string | không | Sort expression in the form `field\|DESC` or `field\|ASC`, e.g. `date\|DESC`. | | `filter` | query | object | không | Endpoint-specific filters, serialised as filter[key]=value. | ## Example request ```bash curl "https://api.tino.vn/v1/contact" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.list_contacts()`, Node.js `await client.account.listContacts();`, PHP `$client->account->listContacts();`. ## Example response ```json { "contacts": null, "page": { "current": 0, "total": 0 } } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Chi tiết liên hệ `GET /v1/contact/@id` · quyền `profile:read` Thông tin và quyền của một liên hệ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/contact/@id` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID liên hệ | ## Example request ```bash curl "https://api.tino.vn/v1/contact/12" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.get_contact(id)`, Node.js `await client.account.getContact(id);`, PHP `$client->account->getContact($id);`. ## Example response ```json { "privileges": { "billing": [ "emails", "newinvoices", "… 11 more item(s)" ], "support": [ "newticket", "tickets", "… 3 more item(s)" ], "disabled_support_departments": [ 2, 3, "… 5 more item(s)" ], "misc": [ "editmain", "manageservicegroups", "… 9 more item(s)" ], "services": { "full": 1, "100001": [ "basic", "billing", "… 18 more item(s)" ], "100002": [ "basic", "billing", "… 23 more item(s)" ], "100003": [ "basic", "billing", "… 5 more item(s)" ] }, "domains": { "full": 1, "200001": [ "basic", "renew", … 25 more line(s) ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Quyền có thể cấp cho liên hệ `GET /v1/contact/privileges` · quyền `profile:read` Các quyền có thể cấp cho liên hệ. Mỗi tên miền và dịch vụ có thể có thêm quyền, tuỳ tính năng. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/contact/privileges` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số Route này không có tham số. ## Example request ```bash curl "https://api.tino.vn/v1/contact/privileges" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.get_contact_privileges()`, Node.js `await client.account.getContactPrivileges();`, PHP `$client->account->getContactPrivileges();`. ## Example response ```json { "privileges": { "billing": [ "emails", "newinvoices", "… 11 more item(s)" ], "support": [ "newticket", "tickets", "… 3 more item(s)" ], "disabled_support_departments": [ 2, 3, "… 5 more item(s)" ], "misc": [ "editmain", "manageservicegroups", "… 9 more item(s)" ], "services": { "full": 1, "100001": [ "basic", "billing", "… 18 more item(s)" ], "100002": [ "basic", "billing", "… 23 more item(s)" ], "100003": [ "basic", "billing", "… 5 more item(s)" ] }, "domains": { "full": 1, "200001": [ "basic", "renew", … 25 more line(s) ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Danh sách liên hệ (contacts) `GET /v1/contacts` · quyền `profile:read` Các liên hệ (tài khoản phụ) của tài khoản. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/contacts` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `page` | query | integer | không | Zero-based page index. page=0 is the first page; the response echoes it 1-based in page.current. Default: `0`. | | `perpage` | query | integer | không | Rows per page. Defaults to the account's RecordsPerPage setting. | | `orderby` | query | string | không | Sort expression in the form `field\|DESC` or `field\|ASC`, e.g. `date\|DESC`. | | `filter` | query | object | không | Endpoint-specific filters, serialised as filter[key]=value. | ## Example request ```bash curl "https://api.tino.vn/v1/contacts" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.list_contacts_legacy()`, Node.js `await client.account.listContactsLegacy();`, PHP `$client->account->listContactsLegacy();`. ## Example response ```json { "contacts": null, "page": { "current": 0, "total": 0 } } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Thông tin tài khoản `GET /v1/details` · quyền `profile:read` Thông tin đăng ký của tài khoản. `verify.phone` (bool) và khối `phone` `{status, verified_at}` cho biết trạng thái số điện thoại; `status` là `verified`, `unverified`, `taken_by_other` hoặc `missing`. `update_required` ở gốc nói về hồ sơ (số giấy tờ, địa chỉ), không về số điện thoại. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/details` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số Route này không có tham số. ## Example request ```bash curl "https://api.tino.vn/v1/details" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.get_details()`, Node.js `await client.account.getDetails();`, PHP `$client->account->getDetails();`. ## Example response ```json { "client": { "id": "700001", "group_id": "0", "email": "user@example.com", "lastlogin": "2026-08-02 10:00:00", "ip": "203.0.113.10", "host": "host.example", "firstname": "Nguyen Van", "lastname": "A", "companyname": "Example Company Ltd", "address1": "123 Example Street", "city": "Phường Bến Thành", "state": "Thành phố Hồ Chí Minh", "country": "VN", "phonenumber": "+84.900000000", "language": "vietnamese", "company": false, "currency_id": "0", "taxid": "0100000000", "nationalid": "000000000000", "birthday": "01/01/1990", "…": "3 more key(s)" }, "update_required": true, "currency": { "code": "đ", "iso": "VND", "sign": "", "format": "1,234.56", "decimal": "0", "id": 0 }, "verify": { "email": "user@example.com" } } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Danh sách thông báo `GET /v1/notifications` · quyền `profile:read` Mọi thông báo trên trang quản lý của tài khoản. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/notifications` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `rel_type` | query | string | không | Optional, return only by relation type | | `rel_id` | query | string | không | Optional, return only by relation id | | `page` | query | integer | không | Zero-based page index. page=0 is the first page; the response echoes it 1-based in page.current. Default: `0`. | | `perpage` | query | integer | không | Rows per page. Defaults to the account's RecordsPerPage setting. | | `orderby` | query | string | không | Sort expression in the form `field\|DESC` or `field\|ASC`, e.g. `date\|DESC`. | | `filter` | query | object | không | Endpoint-specific filters, serialised as filter[key]=value. | ## Example request ```bash curl "https://api.tino.vn/v1/notifications" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.list_notifications()`, Node.js `await client.account.listNotifications();`, PHP `$client->account->listNotifications();`. ## Example response ```json { "notifications": [ { "id": 920001, "client_id": "", "rel_type": "account", "rel_id": "100001", "seen": "0", "subject": "Thông tin tài khoản Hosting tại TinoGroup.", "body": "Dear Nguyen Van A,
\n
\nThông tin tài khoản hosting của bạn đã được khởi tạo.
\n
\nThông tin dịch vụ
\n
\nDịch vụ: WH 1
\nTên miền: example.com
\nThanh toán lần đầu: 79,000 đ
\nThanh toán gia hạn: 79,000 đ
", "rel_type": "ticket", "rel_id": "445776", "seen": "0", "subject": "Nhân viên hỗ trợ đã phản hồi ticket", "body": "On 24 Jul 2026, at 20:18, Nguyen Van A <user@example.com> wrote: Nơi tiếp nhận những yêu cầu hỗ trợ bản khai, xác thực tên miền. Khách hàng có thể liên hệ trực tiếp qua hotline 0364.333.333 nhấn phím 2 \n\nBest Regards!\n\n/----------------…", "metadata": "[]", "type": "direct", "date_added": "2026-07-24 10:00:00", "date_seen": null, "url": false }, "… 12 more item(s)" ], "page": { "total": 14, "pages": 1, "current": 1 } } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Đánh dấu đã đọc thông báo `PUT /v1/notifications/@id/ack` · quyền `profile:write` Đánh dấu thông báo `@id` là đã đọc. Gửi thêm `seen_all=true` để đánh dấu mọi thông báo. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/notifications/@id/ack` | | Method | `PUT` | | Quyền (scope) | `profile:write` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID thông báo | ## Example request ```bash curl -X PUT "https://api.tino.vn/v1/notifications/920001/ack" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:write`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.acknowledge_notification(id)`, Node.js `await client.account.acknowledgeNotification(id);`, PHP `$client->account->acknowledgeNotification($id);`. ## Example response ```json { "id": "171464", "success": true } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Thông báo chưa đọc `GET /v1/notifications/new` · quyền `profile:read` Chỉ các thông báo mới (chưa đọc). ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/notifications/new` | | Method | `GET` | | Quyền (scope) | `profile:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `rel_type` | query | string | không | Optional, return only by relation type | | `rel_id` | query | string | không | Optional, return only by relation id | | `page` | query | integer | không | Zero-based page index. page=0 is the first page; the response echoes it 1-based in page.current. Default: `0`. | | `perpage` | query | integer | không | Rows per page. Defaults to the account's RecordsPerPage setting. | | `orderby` | query | string | không | Sort expression in the form `field\|DESC` or `field\|ASC`, e.g. `date\|DESC`. | | `filter` | query | object | không | Endpoint-specific filters, serialised as filter[key]=value. | ## Example request ```bash curl "https://api.tino.vn/v1/notifications/new" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `profile:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.account.list_new_notifications()`, Node.js `await client.account.listNewNotifications();`, PHP `$client->account->listNewNotifications();`. ## Example response ```json { "notifications": [ { "id": 920001, "rel_type": "account", "rel_id": "100001", "seen": "0", "subject": "Thông tin tài khoản Hosting tại TinoGroup.", "body": "Dear Nguyen Van A,
\n
\nThông tin tài khoản hosting của bạn đã được khởi tạo.
\n
\nThông tin dịch vụ
\n
\nDịch vụ: WH 1
\nTên miền: example.com
\nThanh toán lần đầu: 79,000 đ
\nThanh toán gia hạn: 79,000 đ
# Danh sách dịch vụ `GET /v1/service` · quyền `services:read` Mọi dịch vụ của tài khoản. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `page` | query | integer | không | Zero-based page index. page=0 is the first page; the response echoes it 1-based in page.current. Default: `0`. | | `perpage` | query | integer | không | Rows per page. Defaults to the account's RecordsPerPage setting. | | `orderby` | query | string | không | Sort expression in the form `field\|DESC` or `field\|ASC`, e.g. `date\|DESC`. | | `filter` | query | object | không | Endpoint-specific filters, serialised as filter[key]=value. | ## Example request ```bash curl "https://api.tino.vn/v1/service" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.list()`, Node.js `await client.services.list();`, PHP `$client->services->list();`. ## Example response ```json { "services": [ { "id": "100001", "domain": "example.com", "total": "79000.00", "status": "Active", "billingcycle": "Monthly", "next_due": "2026-08-26", "expires": "2026-08-26", "category": "Platinum Hosting", "category_url": "platinum-hosting", "name": "WH 1" }, { "id": "100002", "domain": "vps-demo.example.net", "total": "199000.00", "status": "Active", "billingcycle": "Monthly", "next_due": "2026-08-26", "expires": "2026-08-26", "category": "NVMe VPS ", "category_url": "nvme-vps", "name": "VPS 20 GB NVMe" }, "… 9 more item(s)" ] } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Chi tiết dịch vụ `GET /v1/service/@id` · quyền `services:read` Thông tin dịch vụ `@id`: gói, chu kỳ, hạn dùng, trạng thái, thông tin đăng nhập dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID dịch vụ | ## Example request ```bash curl "https://api.tino.vn/v1/service/100001" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.get(id)`, Node.js `await client.services.get(id);`, PHP `$client->services->get($id);`. ## Example response ```json { "service": { "id": "100001", "product_id": "2122", "date_created": "2026-07-26", "domain": "example.com", "firstpayment": "79000.00", "total": "79000.00", "billingcycle": "Monthly", "next_due": "2026-08-26", "due_day": "26", "expires": "2026-08-26", "autorenew": "1", "next_invoice": "2026-08-11", "status": "Active", "label": "", "username": "exampleuser", "password": "", "rootpassword": null, "commitment_date": null, "date_suspended": "0000-00-00", "date_terminated": "0000-00-00", "…": "9 more key(s)" }, "addons": [], "haveaddons": [], "unpaid_invoice": [] } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Yêu cầu huỷ dịch vụ `POST /v1/service/@id/cancel` · quyền `services:write` Gửi yêu cầu huỷ dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/cancel` | | Method | `POST` | | Quyền (scope) | `services:write` | | Header | `Authorization: Bearer ` | | Content-Type | `application/json` | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | string | có | ID dịch vụ | | `immediate` | body | string | không | set to false to terminate service at the end of billing date, true - terminate immediately | | `reason` | body | string | không | Reason for this request | ## Example request ```bash curl -X POST "https://api.tino.vn/v1/service/100001/cancel" \ -H "Authorization: Bearer $TINO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "immediate": "", "reason": "" }' ``` `$TINO_TOKEN` là token có quyền `services:write`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.cancel(id, id=...)`, Node.js `await client.services.cancel(id, { id: ... });`, PHP `$client->services->cancel($id, ['id' => ...]);`. ## Example response ```json { "info": [ "cancell_sent" ] } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Các chu kỳ thanh toán `GET /v1/service/@id/cycle` · quyền `services:read` Chu kỳ thanh toán hiện tại và các chu kỳ có thể đổi sang. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/cycle` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID dịch vụ | ## Example request ```bash curl "https://api.tino.vn/v1/service/100001/cycle" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.get_billing_cycles(id)`, Node.js `await client.services.getBillingCycles(id);`, PHP `$client->services->getBillingCycles($id);`. ## Example response ```json { "current": "m", "cycles": [] } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Đổi chu kỳ thanh toán `POST /v1/service/@id/cycle` · quyền `services:write` Đổi chu kỳ thanh toán định kỳ của dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/cycle` | | Method | `POST` | | Quyền (scope) | `services:write` | | Header | `Authorization: Bearer ` | | Content-Type | `application/json` | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | string | có | ID dịch vụ | | `cycle` | body | string | không | New billing cycle | ## Example request ```bash curl -X POST "https://api.tino.vn/v1/service/100001/cycle" \ -H "Authorization: Bearer $TINO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "cycle": "" }' ``` `$TINO_TOKEN` là token có quyền `services:write`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.set_billing_cycle(id, id=...)`, Node.js `await client.services.setBillingCycle(id, { id: ... });`, PHP `$client->services->setBillingCycle($id, ['id' => ...]);`. ## Example response Chưa có mẫu thật: route thay đổi dữ liệu thật hoặc tài khoản thử không có dữ liệu cho route này. Câu trả lời là một đối tượng JSON; lỗi theo dạng chung ở [Gọi API Tino](/docs/api#loi). --- # Tài khoản email của hosting `GET /v1/service/@id/emails` · quyền `services:read` Các tài khoản email trên hosting cPanel của dịch vụ (`listentrys`). ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/emails` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID dịch vụ | | `Name` | undefined | Type | không | Description | | `---` | undefined | --- | không | --- | | `module` | query | string | có | Service type module (Cpanel2\|DirectAdmin2\|Zimbra\|Wilduck) | ## Example request ```bash curl "https://api.tino.vn/v1/service/100001/emails" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.list_email_accounts(id)`, Node.js `await client.services.listEmailAccounts(id);`, PHP `$client->services->listEmailAccounts($id);`. ## Example response ```json { "success": true, "listentrys": null } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Hoá đơn của dịch vụ `GET /v1/service/@id/invoices` · quyền `services:read` Các hoá đơn liên quan đến dịch vụ (`rel_invoices`). ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/invoices` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID dịch vụ | ## Example request ```bash curl "https://api.tino.vn/v1/service/100001/invoices" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.list_invoices(id)`, Node.js `await client.services.listInvoices(id);`, PHP `$client->services->listInvoices($id);`. ## Example response ```json { "success": true, "rel_invoices": null } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Xem nhãn dịch vụ `GET /v1/service/@id/label` · quyền `services:read` Nhãn tự đặt hiện tại của dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/label` | | Method | `GET` | | Quyền (scope) | `services:read` | | Header | `Authorization: Bearer ` | | Content-Type | — (không có body) | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | integer | có | ID dịch vụ | ## Example request ```bash curl "https://api.tino.vn/v1/service/100001/label" \ -H "Authorization: Bearer $TINO_TOKEN" ``` `$TINO_TOKEN` là token có quyền `services:read`. Tham số đường dẫn trong ví dụ là giá trị mẫu. SDK ([SDK & Ví dụ](/docs/sdk)): Python `client.services.get_label(id)`, Node.js `await client.services.getLabel(id);`, PHP `$client->services->getLabel($id);`. ## Example response ```json { "label": "" } ``` Mẫu thật từ tài khoản thử, đã che dữ liệu cá nhân; mảng và chuỗi dài được rút gọn (`… N more item(s)`, `… N more line(s)`). --- # Đặt nhãn dịch vụ `POST /v1/service/@id/label` · quyền `services:write` Đặt nhãn tự đặt để nhận ra dịch vụ. ## HTTP request | Mục | Giá trị | | --- | --- | | URL | `https://api.tino.vn/v1/service/@id/label` | | Method | `POST` | | Quyền (scope) | `services:write` | | Header | `Authorization: Bearer ` | | Content-Type | `application/json` | | Token gọi được | token ứng dụng (`tinoat_`), token API cá nhân (`tinopat_`) | ## Tham số | Tên | Vị trí | Kiểu | Bắt buộc | Mô tả | | --- | --- | --- | --- | --- | | `id` | đường dẫn | string | có | ID dịch vụ | | `label` | body | string | không | New label | ## Example request ```bash curl -X POST "https://api.tino.vn/v1/service/100001/label" \ -H "Authorization: Bearer $TINO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "label": "