Skip to content

List incidents

GET
/incidents
curl --request GET \
--url 'https://app.tunnelhq.com/api/v1/incidents?status=active&limit=200' \
--header 'X-API-Key: <X-API-Key>' \
--header 'X-Project-Id: prj_12'

Returns the project’s incidents. Any role in the project can call it.

Open incidents come first (down before degraded, then the ones nobody has acknowledged), then the rest, newest first. Incidents of paused monitors aren’t listed. error_message is the latest check message during the incident.

Need an API key? See Getting an API key.

X-Project-Id
required
string

The project, as prj_12 or 12. A workspace key can only reach its own workspace’s projects.

Example
prj_12
status
string
Allowed values: active recovered

active for open incidents, recovered for closed ones. Left out (or any other value), both.

limit
integer
default: 200 >= 1 <= 500

How many incidents to consider, before the status filter.

The incidents.

Media typeapplication/json
object
incidents
required
Array<object>
object
id
required
string
server_id
required
string
server_name
required
string
status
required

active while the incident is open.

string
Allowed values: active recovered
severity
required

critical for a down incident, warning for a degraded one.

string
Allowed values: critical warning
started_at
required

ISO 8601, UTC.

string
ended_at
required

ISO 8601, UTC. null while open.

string | null
acknowledged
required
boolean
acknowledged_at
required

ISO 8601, UTC.

string | null
error_type
required

The incident’s level: down or degraded.

string
error_message
required

A check message from the incident.

string | null
total
required

Incidents returned.

integer
active
required

Open incidents among the ones considered, whatever status you sent.

integer
Example
{
"incidents": [
{
"id": "inc_318",
"server_id": "srv_57",
"server_name": "sg-vless-01",
"status": "active",
"severity": "critical",
"started_at": "2026-09-25T13:12:40.000Z",
"ended_at": null,
"acknowledged": false,
"acknowledged_at": null,
"error_type": "down",
"error_message": "Tunnel unreachable"
}
],
"total": 1,
"active": 1
}
X-RateLimit-Limit
integer

Requests the workspace’s plan allows per minute.

X-RateLimit-Remaining
integer

Requests left in the current minute.

X-RateLimit-Reset
integer

Unix time, in seconds, when the current minute ends.

The X-Project-Id header is missing or malformed.

Media typeapplication/json
object
error
required
boolean
code
required

The HTTP status, repeated.

integer
message
required

What went wrong.

string
details

More detail, on some errors.

retry_after

Seconds to wait, on the 429 for wrong keys.

integer
Examples
{
"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.

Media typeapplication/json
object
error
required
boolean
code
required

The HTTP status, repeated.

integer
message
required

What went wrong.

string
details

More detail, on some errors.

retry_after

Seconds to wait, on the 429 for wrong keys.

integer
Examples
{
"error": true,
"code": 401,
"message": "API key is required. Provide X-API-Key header or Authorization: Bearer <key>"
}

The key can’t reach this project.

Media typeapplication/json
object
error
required
boolean
code
required

The HTTP status, repeated.

integer
message
required

What went wrong.

string
details

More detail, on some errors.

retry_after

Seconds to wait, on the 429 for wrong keys.

integer
Examples
{
"error": true,
"code": 403,
"message": "This API key is scoped to a different organization"
}

No active project has this ID.

Media typeapplication/json
object
error
required
boolean
code
required

The HTTP status, repeated.

integer
message
required

What went wrong.

string
details

More detail, on some errors.

retry_after

Seconds to wait, on the 429 for wrong keys.

integer
Example
{
"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.

Media typeapplication/json
One of:
object
error
required
string
Allowed values: Rate limit exceeded Daily limit exceeded Monthly limit exceeded
message
required
string
retry_after

Seconds to wait. Absent for the monthly limit.

integer
Examples
{
"error": "Rate limit exceeded",
"message": "Per-minute limit of 60 requests exceeded",
"retry_after": 60
}
Retry-After
integer

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.

Media typeapplication/json
object
error
required
boolean
code
required

The HTTP status, repeated.

integer
message
required

What went wrong.

string
details

More detail, on some errors.

retry_after

Seconds to wait, on the 429 for wrong keys.

integer
Example
{
"error": true,
"code": 500,
"message": "Internal server error"
}