No matching sections.
Status pages
A status page is the public face of your monitoring: a permanent slug, an ordered set of
components, and the incidents you declare on it. Everything below sits under
/statuspage and reads
statuspage:read / statuspage:write - its own scope
family, so a token can manage the page without touching monitors or contacts.
/monitor/incident) is derived - the checking engine opened it
because a monitor went down. A status-page incident is declared - it is what the owner says is
happening, in the owner's words, and it exists whether or not a check failed.
Pages
| Operation | Scope |
|---|---|
GET /statuspage | statuspage:read |
GET /statuspage/{id} | statuspage:read |
POST /statuspage | statuspage:write |
PATCH /statuspage/{id} | statuspage:write |
DELETE /statuspage/{id} | statuspage:write |
The list is small and closed - it answers the standard envelope but never pages - and it sorts by
created, title or slug
(see the query surface for the spelling).
{
"id": "…",
"slug": "acme",
"title": "Acme status",
"componentCount": 4,
"unresolvedIncidents": 0,
"hasPassword": false,
"created": 1785712608,
"customDomain": null,
"settings": {
"homepageUrl": "https://acme.example.com",
"theme": "…", "themeColor": "…",
"density": "wide", // wide | compact
"logoAlignment": "left", // left | center
"showGroups": true,
"robotsIndex": true,
"hideBranding": false,
"autoAddMonitors": false,
"features": [ /* named tokens - never a bitmask */ ],
"slaTarget": 99.9
},
"components": [ /* ordered - see below */ ]
}
created, componentCount and
unresolvedIncidents - so following a list row to its detail never loses a member.
(It published fewer members than its own list row until 2026-08-17, which is the sort of thing you
only discover after writing the client.)
POST /statuspage takes {slug, title} - both
required - plus optional settings and components, and
answers 201 + Location; the plan's page cap is
enforced. The slug is permanent: it is the page's public address, so pick it deliberately.
PATCH changes the title and settings members - only what you send
changes, and an explicit null clears a member rather than being ignored.
DELETE answers the standard receipt and frees the slug:
{
"id": "…", "deleted": true, "type": "statusPage",
"slug": "acme", "title": "Acme status",
"cascaded": { "components": 4, "incidents": 12, "subscribers": 38, "templates": 3 }
}
Components
PUT /statuspage/{id}/component replaces the whole component set.
It is a PUT rather than a PATCH on purpose: the array's order is the display order, and there is no
coherent way to express "insert here" in a partial update.
id in the new array. A component you send
without an id is a NEW component - and per-component subscriptions belong to the id, so dropping it silently
unsubscribes everyone who was watching that component.
An item is {id?, monitorId? | thirdParty, name?, group?, manualState?}:
| Member | Meaning |
|---|---|
id | Present = keep this component (and its subscriptions). Absent = create one. |
monitorId | The monitor whose state drives it. Must be one of your own monitors. |
thirdParty | The alternative to monitorId: a component nothing checks, whose state you pin by hand. |
name | The display name. It is name, not label - a component is an entity, and every entity on this surface carries a name. |
group | Optional grouping heading. |
manualState | operational | degraded | down, and third-party components only - a monitored component's state comes from its monitor. Spelled manualStatus until 2026-08-17. |
The plan's component cap is enforced on the whole set, and Idempotency-Key is
honoured.
Declared incidents
| Operation | Notes |
|---|---|
GET /statuspage/{id}/incident | Newest first, each with its full timeline[]. |
GET /statuspage/{id}/incident/{incidentId} | One incident, timeline and postmortem. |
POST /statuspage/{id}/incident | Declare one. Idempotency-Key REQUIRED |
PATCH /statuspage/{id}/incident/{incidentId} | Fix title / kind / components; set or clear the postmortem. The timeline is untouched. |
POST /statuspage/{id}/incident/{incidentId}/timeline | Append an entry. Idempotency-Key REQUIRED |
DELETE /statuspage/{id}/incident/{incidentId} | Delete it. No subscriber notice, matching the dashboard. |
Idempotency-Key: a keyless retry after a timeout announces the incident twice, to
everybody. Mint one key per logical declaration and reuse it for that declaration's retries only - see
Jobs & idempotency.
The write body is {title, state, message, componentIds?, kind?, scheduledStart?,
scheduledEnd?, impact?}. The initial state seeds the timeline together with
message - so one call both declares the incident and posts its first update.
curl -X POST 'https://api2.host-tracker.com/statuspage/PAGE_ID/incident' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: incident-2026-08-17-checkout' \
-d '{
"title": "Checkout is failing for some customers",
"state": "investigating",
"message": "We are looking into elevated errors on checkout.",
"componentIds": ["…"],
"impact": "major"
}'
{
"id": "…",
"title": "Checkout is failing for some customers",
"state": "investigating", // investigating | identified | monitoring | resolved
"kind": "incident", // incident | maintenance
"impact": "major", // minor | major
"created": 1785712608,
"resolvedAt": null,
"scheduledStart": null, "scheduledEnd": null,
"componentIds": ["…"],
"componentNames": ["Checkout"],
"postmortem": null,
"timeline": [
{ "state": "investigating", "message": "We are looking into elevated errors on checkout.", "at": 1785712608 }
]
}
state, on the row, in every timeline entry and in both
write bodies. It was status until 2026-08-17, when this family joined the
surface-wide rule that state means "where something is in its lifecycle" - the
same word a monitor, a job, a maintenance window and an instant check use. There is no alias: the old spelling
binds nothing and the old member is simply absent. The affected components likewise ride as
componentIds + componentNames
(was componentLabels).
A maintenance is the same resource with kind: "maintenance" and a
Unix-seconds window in scheduledStart/scheduledEnd.
The timeline
An incident is a story, not a flag, and the timeline is where it is told. Each entry is
{state, message, at}, appended with:
curl -X POST 'https://api2.host-tracker.com/statuspage/PAGE_ID/incident/INCIDENT_ID/timeline' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: incident-…-update-3' \
-d '{ "state": "resolved", "message": "Checkout is fully recovered." }'
Posting resolved stamps the incident's
resolvedAt - once; a later entry does not move it.
…/update until 2026-08-17, and the operation was called
addStatusPageIncidentUpdate - a verb in a url whose every other segment is a
resource, and one that read as "update the incident" beside the incident's own
PATCH door. The old path answers 405 with
allowed[], never a silent accept.
Incident templates
Presets for the incidents you declare repeatedly: GET and
POST /statuspage/{id}/template
({title, message, defaultImpact?}, 201 +
Location), and
DELETE /statuspage/{id}/template/{templateId}. There is deliberately no update:
a template is cheap to re-create, and an editable preset is a preset two people can disagree about.
Membership of THIS page is checked on delete, so a 200 always means the template
really was here. Its receipt carries no cascaded block at all -
a template cascades to nothing, and a block of zeroes would suggest it might.
Subscribers
| Operation | Notes |
|---|---|
GET /statuspage/{id}/subscriber | Emails (with their double-opt-in state) and push channels. |
POST /statuspage/{id}/subscriber | Add a push channel: {kind: webhook|slack|teams, url, componentId?}. Plan subscriber cap enforced. |
DELETE /statuspage/{id}/subscriber/{subscriberId} | Remove one of any kind. 404 when it is not this page's. |
confirmedAt) and remove them; it cannot add one, because an API that could would be
a way to sign somebody else up.
componentId scopes a subscriber to one component, so a channel can follow just the
part it cares about. A row reads
{id, kind, email?, url?, componentId?, confirmedAt?, created}.
What stays in the dashboard
This family covers configuration, components, incidents, templates and subscribers. Three things are deliberately not here, and are managed in the web dashboard:
- The public rendering - the page itself, its
status.jsonand its badges. Those are the public surface, not this API. - The page password.
- The custom-domain lifecycle -
customDomainis readable here, but claiming and verifying one is a dashboard flow.