Skip to content

Post an incident

POST
/status-pages/{id}/incidents
curl --request POST \
--url https://app.tunnelhq.com/api/v1/status-pages/sp_12/incidents \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <X-API-Key>' \
--header 'X-Project-Id: prj_12' \
--data '{ "title": "Frankfurt tunnels are slow", "impact": "degraded", "status": "investigating", "message": "We are looking into slow connections through Frankfurt.", "service_ids": [ "sps_31" ] }'

Posts an incident on the page, with its first update. It is public at once. message is plain text; web addresses in it become links on the public page. It needs a role that can edit monitors (Owner, Admin and Manager have it by default).

Need an API key? See Getting an API key.

id
required
string

The page’s id (sp_12), from List status pages. The bare number (12) works too.

Example
sp_12
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
Media typeapplication/json
object
title
required
string
<= 200 characters
impact
required

How badly the incident affects the services. degraded_performance, partial_outage, major_outage and full_outage are also accepted on input.

string
Allowed values: degraded partial full
status
string
default: investigating
Allowed values: investigating identified monitoring
message
required

Plain text. Web addresses in it become links.

string
<= 5000 characters
service_ids
required

The page’s services (sps_ IDs, from Get a status page) the incident affects.

Array<string>
>= 1 items
Example
{
"title": "Frankfurt tunnels are slow",
"impact": "degraded",
"status": "investigating",
"message": "We are looking into slow connections through Frankfurt.",
"service_ids": [
"sps_31"
]
}

The incident, public at once.

Media typeapplication/json
object
id
required
string
title
required
string
impact
required

How badly the incident affects the services. degraded_performance, partial_outage, major_outage and full_outage are also accepted on input.

string
Allowed values: degraded partial full
status
required
string
Allowed values: investigating identified monitoring resolved
source
required

auto opened by itself when a service went down.

string
Allowed values: auto manual
edited
required

Someone has posted to it. An auto incident then no longer closes by itself.

boolean
started_at
required
string format: date-time
resolved_at
required
string | null format: date-time
service_ids
required
Array<string>
updates
required

Newest first.

Array<object>
object
id
required
integer
status
required
string
Allowed values: investigating identified monitoring resolved
message
required

Plain text.

string
at
required
string format: date-time
Examples
Exampledefault

A status page incident

{
"id": "spi_7",
"title": "Frankfurt tunnels are slow",
"impact": "degraded",
"status": "investigating",
"source": "manual",
"edited": true,
"started_at": "2026-11-07T08:12:00.000Z",
"resolved_at": null,
"service_ids": [
"sps_32"
],
"updates": [
{
"id": 1,
"status": "investigating",
"message": "We are looking into slow connections through Frankfurt.",
"at": "2026-11-07T08:12:00.000Z"
}
]
}
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 body is invalid: title, message or service_ids is missing, or impact or status isn’t allowed.

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": "impact must be one of degraded, partial, full, degraded_performance, partial_outage, major_outage, full_outage."
}

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 role can’t edit monitors.

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": 403,
"message": "Posting status page incidents needs a role that can edit monitors in this project."
}

The project has no status page with 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": "No such status page."
}

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"
}