Getting started with Tino Uptime
Tino Uptime checks websites, servers, service ports, DNS records, SSL certificates and domain expiry from probes in Vietnam and abroad. When a target fails, Tino Uptime opens an incident and alerts by email, Telegram, Discord, Slack, webhook or Zalo. The service API lets your application manage monitors and read uptime, check results, incidents and alert channels of a Tino Uptime plan.
Updated: 2026-10-24. Sources: Tino's Tino Uptime module and the Tino Uptime OpenAPI.
Calling the API
| Item | Value |
|---|---|
| Address | https://api.tino.vn/service/<service ID>/uptime/… |
| Authentication | Authorization: Bearer <token>: the Tino Uptime service owner's sign-in token |
| Body | JSON, Content-Type: application/json |
| Each route | the Tino Uptime section of the API Reference |
- The body is always JSON. With Update a monitor, send only the fields to change.
- Only the parameters listed on each route are relayed. Tino Uptime refuses unknown body fields (422
validation_failed). - Monitor, incident and channel IDs in the path are UUIDs; a malformed one answers 400
invalid_request. - What this API does not cover (status pages, servers, WordPress, CVE alerts) opens in the Tino Uptime dashboard through the
login_urlof the plan overview.
The /v1 gateway does not expose the Tino Uptime routes yet: app tokens (tinoat_) and personal API tokens (tinopat_) cannot call them. The sign-in token is the one customers use in the tino.vn client area; the SDK gets it with an OTP sign-in:
from tino_userapi import TinoClient
client = TinoClient()
client.request_login_otp("you@example.com")
client.verify_login_otp("you@example.com", input("OTP code: "))
print(client.request("GET", "/service/100002/uptime/monitors", query={"state": "down"}))100002 is the Tino Uptime service ID: how to find it is below.
Find the Tino Uptime service
Each Tino account has one Tino Uptime account; the current plan belongs to exactly one service.
- Identify it by the service's module: Service details (
GET https://api.tino.vn/service/<id>, same sign-in token) hasservice.acc_moduleset to"tino_uptime". Candidates come from the service list. - Call the plan overview (
GET /service/<id>/uptime):
| Result | Meaning |
|---|---|
| 200 | the customer's current Tino Uptime plan: call the other routes with this ID |
404 service_not_linked | the service is no longer the current plan (the customer moved to another service): try the next Tino Uptime service |
404 invalid method | the service is not Tino Uptime or does not exist |
404 service_not_found | the service belongs to another account |
404 account_not_found | no Tino Uptime account for the service yet: contact Tino support |
Plan limits
Limits are in subscription.limits of the plan overview, current numbers in usage. Read the limits from the API, do not hard-code them: each plan's numbers may change.
| Field | Meaning |
|---|---|
max_monitors | maximum number of monitors |
min_interval_s | shortest check interval (seconds) |
raw_retention_days | days of per-check results you can read |
locations | probe locations you can use: vn-cmc, vn-vt (Vietnam), intl (international) |
channels | alert channel types you can create |
Going over a limit answers 403 entitlement_exceeded; details.resource names the limit (monitors, min_interval_s, locations, channels). While the service is suspended, the Tino Uptime account is read-only: writes answer 403 account_suspended. After a downgrade, monitors over the limit are paused (disabled_reason: paused_by_plan, counted in monitors_paused_by_plan).
Monitor types
Create a monitor takes name, interval_s (30–86400 seconds, not below limits.min_interval_s), locations and settings. settings.type decides the other fields:
type | Required | Optional |
|---|---|---|
http | url | method (GET, HEAD, POST), expected_status (array of HTTP codes, up to 20), follow_redirects (default true), max_latency_ms (1–60000), headers (object), body (up to 4096 characters), basic_auth (username, password) |
keyword | url, keyword (1–100 characters) | mode (present, absent), case_sensitive, method (GET, POST) and the other http options |
ssl | host | port (443, 465, 993, 995), warn_days (1–90, default 14) |
domain | domain | warn_days (1–120, default 30) |
ping | host | — |
tcp | host, port (1–65535) | — |
dns | name, record_type (A, AAAA, CNAME, MX, NS, TXT) | expected (array of values, up to 20), resolver (an IP, or an IP with port 53; empty asks the authoritative name servers) |
heartbeat | — | grace_s (0–86400, default 300) |
heartbeatworks the other way round: your system callssettings.ping_urlafter each run.ping_urlis only in the create answer: store it right away.- Headers, body and the Basic auth password are never returned;
settingsonly tellsheader_names,body_set,basic_auth_set. international_critical: true: a failure seen only by the international probe also counts as down (defaultfalse).- Internal or unsafe targets are refused: 422
validation_failedwithdetails.reason: blocked_destination. A target checked too often (counting other customers) answers 422target_rate_exceeded: pick a longer interval.
A monitor's state: pending (no result yet), up, suspect, down, partial, down_international, paused (turned off, stopped by the system per disabled_reason, or within paused_until).
Alert channels
Create a channel with a kind from the plan's limits.channels; a new channel awaits verification (except an email to the account owner's own verified address). A channel without opted_in_at receives nothing.
kind | config | Verification (verification.method) |
|---|---|---|
email | address | email_code: send the code from the email to Verify an alert channel (code); the code is valid 24 hours |
telegram | — | telegram_link: open telegram_url (or telegram_group_url for a group) within 10 minutes |
discord, slack, webhook | url (https) | test_message: call Verify to send a test message; the channel is verified when it gets through |
zalo | consent: true; phone to verify by OTP, no phone to link through the OA | zalo_otp or zalo_link (send zalo_link_code to the OA at zalo_oa_url, valid 10 minutes) |
- A webhook channel returns
webhook_secret(whsec_…) once only, in the create answer: store it to check the signature of incoming messages. - Verification emails: at most 5 an hour per account and 3 a day per address; beyond that 429
rate_limited. A wrong code answers 422token_invalid. - Send a test message works only for a verified, enabled channel; otherwise 409
conflict.
Lists and safe retries
Lists (monitors, incidents, channels, per-check results) use cursor pagination: send the previous page's next_cursor as cursor; next_cursor is null at the end. limit defaults to 50, at most 100 (per-check results: default 100, at most 1000).
{ "data": { "data": [], "next_cursor": null } }Create a monitor and Create an alert channel take idempotency_key (8–128 characters A-Za-z0-9._:-). If the connection drops midway, resend the same body with the same key: nothing extra is created. The same key with a different body, or while the earlier call is still running, answers 409 idempotency_conflict. Without a key every call is a new command: read the list again before retrying.
Responses
Success: {"data": …}, where data is Tino Uptime's answer. HTTP 200, 201 on create, 202 once a test message is queued, 204 on delete (no content). Times are RFC 3339; IDs are UUIDs.
Errors
{ "error": ["entitlement_exceeded"], "message": "Đã vượt hạn mức của gói.", "details": { "resource": "monitors" }, "request_id": "…" }Branch on error[0], not on message (a Vietnamese sentence that may change). With validation_failed, details.field names the wrong field and details.reason the reason when there is one. Errors Tino returns before relaying (service_not_found, invalid method) only have error. When reporting a problem to Tino, include request_id.
| HTTP | Code | Meaning, what to do |
|---|---|---|
| 400 | invalid_request | malformed ID (not a UUID), malformed idempotency_key, or a bad request: a bug on the application side |
| 401 | unauthorized, invalid_token, token_expired | the sign-in token is wrong or expired: refresh it |
| 403 | account_suspended | the Tino Uptime account is suspended: writes are blocked, GET still works |
| 403 | entitlement_exceeded | over a plan limit, details.resource names it: upgrade or remove monitors, channels |
| 404 | service_not_found, invalid method | not a Tino Uptime service of the signed-in account: go back to the service list |
| 404 | service_not_linked | the service is no longer the current plan: find the service again (Find the Tino Uptime service) |
| 404 | account_not_found | no Tino Uptime account yet: contact Tino support |
| 404 | not_found | the monitor, incident or channel does not exist or was deleted: reload the list |
| 409 | conflict | not possible in the current state (e.g. a test message to an unverified channel): reload and retry |
| 409 | idempotency_conflict | same idempotency_key with a different body, or the earlier call is still running |
| 422 | validation_failed | invalid data: show the error under the field named by details.field |
| 422 | target_rate_exceeded | the target is checked too often (counting other customers): pick a longer interval |
| 422 | token_invalid | the email channel's verification code is wrong or expired |
| 429 | rate_limited | too fast: retry later |
| 502, 503 | network, invalid_response, not_configured, unavailable | the connection between Tino and Tino Uptime is interrupted: a Tino-side error, not a token problem. Do not sign out, retry later |