List a monitor's results
const url = 'https://app.tunnelhq.com/api/v1/results/server/srv_42?period=15m&limit=500&offset=0&status=healthy';const options = {method: 'GET', headers: {'X-Project-Id': 'prj_12', 'X-API-Key': '<X-API-Key>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://app.tunnelhq.com/api/v1/results/server/srv_42?period=15m&limit=500&offset=0&status=healthy' \ --header 'X-API-Key: <X-API-Key>' \ --header 'X-Project-Id: prj_12'Returns one monitor’s results, a tunnel’s or an Uptime check’s, newest first (ties broken
by ID), a page at a time: up to limit results, starting at offset. Any role in the
project can call it. Results older than 24 hours are thinned as described in
List results.
total counts every result that matches the filters, so you can page through them.
success_rate covers the whole period, whatever page or status you ask for.
Need an API key? See Getting an API key.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters”The monitor, as srv_42 or 42.
Example
srv_42Header Parameters
Section titled “Header Parameters”The project, as prj_12 or 12. A workspace key can only reach its own workspace’s projects.
Example
prj_12Query Parameters
Section titled “Query Parameters”How far back to look. Any other value is refused with 400 “period must be 15m, 1h, 24h or 7d.”
The most results to return, from 1 to 1000. Anything else is refused with 400 “limit must be a whole number from 1 to 1000.”
How many matching results to skip. Anything other than a whole number, 0 or more, is refused with 400 “offset must be a whole number, 0 or more.”
Only results with this status. Left out or empty, no filter. up is accepted as healthy. Anything else is refused with 400 “status must be healthy, down or degraded.”
Responses
Section titled “ Responses ”The monitor’s results.
object
object
degraded means the check had no verdict; unknown, that it ran during maintenance.
The check’s time, in milliseconds: for a tunnel, one round trip through it; for an Uptime check, as described for the monitor’s latency_ms. Null when the check failed or measured none.
Tunnel results only. How long the tunnel took to come up, in milliseconds. Null when the check failed or measured none. For VLESS, VMess, Trojan, Shadowsocks, Hysteria2, and TUIC, it’s the time to first contact with the server.
A tunnel’s protocol, or an Uptime check’s type: http, keyword, ping, port, dns, or push.
When the check ran, in UTC, as YYYY-MM-DD HH:MM:SS with no time zone marker.
What the check said when it failed, such as “Tunnel unreachable”.
Results matching the filters, across every page.
Percent of the whole period’s results that were healthy, rounded, whatever page or status you asked for. null when there are none.
Example
{ "server_id": "srv_42", "server_name": "fra-wg-01", "results": [ { "id": "hb_9912345", "server_id": "srv_42", "server_name": "fra-wg-01", "status": "healthy", "latency_ms": 157, "connect_ms": 364, "protocol": "wireguard", "tested_at": "2026-09-25 14:30:02", "error_message": null } ], "period": "24h", "total": 1, "success_rate": 100}Headers
Section titled “Headers”Requests the workspace’s plan allows per minute.
Requests left in the current minute.
Unix time, in seconds, when the current minute ends.
The monitor ID isn’t a valid ID, a query parameter is out of range, or the X-Project-Id header is missing or malformed.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 400, "message": "Invalid server ID"}{ "error": true, "code": 400, "message": "status must be healthy, down or degraded."}{ "error": true, "code": 400, "message": "offset must be a whole number, 0 or more."}{ "error": true, "code": 400, "message": "X-Project-Id header is required (e.g. prj_1 or numeric id)"}The API key is missing, wrong, expired, switched off, or no longer valid.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 401, "message": "API key is required. Provide X-API-Key header or Authorization: Bearer <key>"}{ "error": true, "code": 401, "message": "Invalid or expired API key"}{ "error": true, "code": 401, "message": "API key has expired"}{ "error": true, "code": 401, "message": "API key owner account is inactive"}{ "error": true, "code": 401, "message": "This API key's workspace access has been removed"}The key can’t reach this project.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 403, "message": "This API key is scoped to a different organization"}{ "error": true, "code": 403, "message": "You do not have access to this project"}The project has no such monitor, or the project doesn’t exist.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 404, "message": "Server not found"}{ "error": true, "code": 404, "message": "Project not found or inactive"}A usage limit was reached, or this IP address made too many requests with a wrong key.
Usage limits are per workspace and plan: per minute (Retry-After: 60), per day
(Retry-After: 3600), and per month (no Retry-After). They use their own body shape.
An IP address may send 10 wrong keys a minute; one more is allowed every 6 seconds. While
that allowance is used up, every request from the address is refused, even one with a
valid key.
object
Seconds to wait. Absent for the monthly limit.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": "Rate limit exceeded", "message": "Per-minute limit of 60 requests exceeded", "retry_after": 60}{ "error": "Daily limit exceeded", "message": "Daily limit of 25000 requests exceeded", "retry_after": 3600}{ "error": "Monthly limit exceeded", "message": "Monthly limit of 250000 requests exceeded"}{ "error": true, "code": 429, "message": "Too many failed API key attempts from this address. Wait a few seconds and try again.", "retry_after": 6}Headers
Section titled “Headers”Seconds to wait. 60 for the per-minute limit, 3600 for the daily limit, 6 after wrong keys. Absent for the monthly limit.
Something failed on TunnelHQ’s side.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Example
{ "error": true, "code": 500, "message": "Internal server error"}