PublicStatus API

Update your status page from anywhere — let your monitoring, CI or scripts open and resolve incidents, flip a component to degraded, or schedule maintenance. No browser, no login: a long-lived Personal Access Token carries the request.

Quickstart

  1. In the admin, open Settings → API Tokens and create a token (available from the Team plan). The kpat_… value is shown once — copy it.
  2. Point requests at your status domain: https://status.example.com/api/write for changes, /api/query for reads.
  3. Send the token as a bearer header. The tenant is resolved from the token — you never pass a tenant id.
curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:incident:open",
    "payload": { "title": "Elevated API latency", "body": "We are investigating.", "severity": "minor" }
  }'

Authentication

Every request carries a Personal Access Token in the Authorization header:

Authorization: Bearer kpat_your_token_here
Bearer requests are exempt from CSRF and cookies — the token alone authenticates the call. Treat it like a password.

Scopes

Each scope comes in a read and a write variant. A token only receives the scopes you tick when creating it.

ScopeGrants
incidentsOpen, post updates to, and resolve incidents
maintenanceSchedule, start, complete and cancel maintenance windows
componentsCreate, update and delete components (the service list)

Request format

All calls are POST with a JSON envelope. type is the action, payload its parameters:

POST /api/write        { "type": "<action>", "payload": { … } }   // writes
POST /api/query        { "type": "<action>", "payload": { … } }   // reads

A successful write responds { "isSuccess": true, "data": { … } }. For component endpoints, the created/updated row (with its id and version) is in data.data; incident/maintenance endpoints respond with their own smaller data shape (see the note under each). Reads respond { "data": { "rows": [ … ] } }.

Incidents

Open an incident — publicstatus:write:incident:open

Fields: title, body (the first update), severity (minor · major · critical, default minor), optional componentIds (components to flag as affected), optional startedAt (ISO-8601).

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:incident:open",
    "payload": {
      "title": "Elevated API latency",
      "body": "We are investigating elevated response times.",
      "severity": "major",
      "componentIds": ["019f288c-2cf7-7631-b12b-0fca8db39544"]
    }
  }'

The response's data.id is the incident id — keep it to post updates and resolve.

Post an update — publicstatus:write:incident:post-update

Fields: incidentId, body, optional newStatus (investigating · identified · monitoring · resolved).

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:incident:post-update",
    "payload": { "incidentId": "019f28a1-....", "body": "Root cause identified, rolling out a fix.", "newStatus": "identified" }
  }'

Resolve an incident — publicstatus:write:incident:resolve

Fields: incidentId, body (the closing note).

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:incident:resolve",
    "payload": { "incidentId": "019f28a1-....", "body": "Latency back to normal. Resolved." }
  }'

Components

Components are the services shown on your page. Status values: operational · degraded-performance · partial-outage · major-outage · under-maintenance.

Create — publicstatus:write:component:create

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:component:create",
    "payload": { "name": "API", "description": "Public HTTP API", "status": "operational", "displayOrder": 0, "showOnPage": true }
  }'

Update (flip the status) — publicstatus:write:component:update

Send the component id, its current version (optimistic concurrency) and the changes. This is what an alert integration calls to turn a service red or green.

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:component:update",
    "payload": { "id": "019f288c-2cf7-7631-b12b-0fca8db39544", "version": 1, "changes": { "status": "major-outage" } }
  }'

Delete — publicstatus:write:component:delete

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "publicstatus:write:component:delete", "payload": { "id": "019f288c-....", "version": 1 } }'

Maintenance

Schedule — publicstatus:write:maintenance:schedule

Fields: title, body, scheduledStart + scheduledEnd (ISO-8601), optional componentIds.

curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:maintenance:schedule",
    "payload": {
      "title": "Database upgrade",
      "body": "Brief read-only window during the upgrade.",
      "scheduledStart": "2026-07-10T02:00:00Z",
      "scheduledEnd": "2026-07-10T03:00:00Z",
      "componentIds": ["019f288c-2d6b-72aa-a5b0-feaf8a38ea37"]
    }
  }'

Start / Complete / Cancel

Each takes the maintenance id and its current version:

# start:    "type": "publicstatus:write:maintenance:start"
# complete: "type": "publicstatus:write:maintenance:complete"
# cancel:   "type": "publicstatus:write:maintenance:cancel"
curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "publicstatus:write:maintenance:start", "payload": { "id": "019f28b0-....", "version": 1 } }'

Reading data

With a read scope you can list your components and incidents — handy to look up ids before updating.

# list components (returns id, name, status, version, …)
curl -X POST https://status.example.com/api/query \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "publicstatus:query:component:list", "payload": {} }'

# list incidents
curl -X POST https://status.example.com/api/query \
  -H "Authorization: Bearer kpat_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "publicstatus:query:incident:list", "payload": {} }'

Guide: drive the page from Prometheus Alertmanager

The most common setup: your monitoring already knows when a service is down — wire it straight to the status page. Alertmanager can POST a webhook per alert; a tiny adapter translates that into API calls.

1. Add a webhook receiver

Alongside your existing receivers (Slack, Telegram, …), add one that points at your adapter:

receivers:
  - name: statuspage
    webhook_configs:
      - url: http://statuspage-bridge/alert   # your adapter
        send_resolved: true                    # so 'resolved' closes the incident

route:
  routes:
    - matchers: [ 'statuspage="true"' ]        # opt individual alerts in
      receiver: statuspage
      group_by: [ alertname, component ]

Tag the alerts you want on the page with a label, e.g. statuspage: "true" and a component label naming the affected service.

2. Map the webhook to API calls

Alertmanager sends a batch with status: "firing" | "resolved" and each alert's labels. The adapter's logic:

A firing webhook, translated, is exactly the call from the top of this page:

# adapter receives Alertmanager JSON, then:
curl -X POST https://status.example.com/api/write \
  -H "Authorization: Bearer $STATUSPAGE_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "publicstatus:write:incident:open",
    "payload": { "title": "HighLatency on studio", "body": "Alert firing since 15:04Z.", "severity": "major" }
  }'
Give the adapter's token only the scopes it needs — incidents:write and (if it flips component status) components:write. Store the kpat_… as a secret in your cluster, never in the alert config.

Errors

Failures return a non-2xx status and { "isSuccess": false, "error": { … } }. Common cases:

StatusMeaning
401Missing, malformed, revoked or expired token
403 feature_disabledYour plan doesn't include the API — upgrade to Team
403The token wasn't granted a scope covering this action
400 / 422Invalid payload, or a plan limit reached (e.g. component cap)