Tino Developers
Xem .md

SDK & Ví dụ

SDK chính thức của Tino cho Python, Node.js và PHP, mã nguồn mở ở tinovn/tino-sdk (giấy phép MIT). Mỗi route có một hàm client.<nhóm>.<thao tác>(); 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àiPhiên bản đang phát hànhYêu cầu
Pythonpip install tino-userapi1.2.0 (PyPI)Python 3.8+, không phụ thuộc gói khác
Node.jsnpm install @tinovn/tino-sdk1.1.0 (npm)Node.js 18+, ESM, có định nghĩa TypeScript, không phụ thuộc gói khác
PHPcomposer require tinovn/tino-sdk1.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 (tinopat_) hoặc access token của Đăng nhập bằng Tino (tinoat_). Token đọc từ biến môi trường TINO_TOKEN, không ghi vào mã nguồn.

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())
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
require "vendor/autoload.php";

$client = new Tino\UserApi\TinoClient(["baseUrl" => "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 rồi tạo client với token mới.

Gọi một route

Mỗi trang route ở API 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):

client.dns.create_record("100003", "500001", name="www", type="A", content="203.0.113.10", ttl=3600, priority=0)
await client.dns.createRecord("100003", "500001", { name: "www", type: "A", content: "203.0.113.10", ttl: 3600, priority: 0 });
$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ó):

records = client.request("GET", "/domain/200001/dns")
const records = await client.request("GET", "/domain/200001/dns");
$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ốngPython, Node.jsPHP
HTTP 401 invalid_token (token sai, hết hạn, đã thu hồi)TinoAuthErrorTinoAuthException
HTTP 403 insufficient_scope, ip_not_allowedTinoApiErrorTinoApiException
Không tìm thấyTinoNotFoundErrorTinoNotFoundException
Dữ liệu gửi lên saiTinoValidationErrorTinoValidationException
Bị giới hạn tần suấtTinoRateLimitErrorTinoRateLimitException
Lỗi mạng, hết thời gian chờTinoTransportErrorTinoTransportException

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):

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):

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):

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.