Worked status-page samples
The operations below document each route’s query and path parameters; this overlay walks the integration an embedder actually ships: read the feed → open one incident’s timeline → optionally parse the RSS → wire up the subscriber flow. The whole surface is unauthenticated — a status page is a public trust signal — so none of the calls needX-API-Key, and every
read is edge-cached (s-maxage=60, so a 60-second poll interval is
pointless; polls on a one-to-two-minute cadence hit the edge for free).
Read and incident-write are split across roles on purpose: anyone with the
URL can render the page, while publishing or updating an incident is a
tenant-authenticated control-plane action from the dashboard Settings →
Platform status surface (the status-page
guide walks that console flow). This page documents
the public read and subscriber surface — there is no API-key-gated
incident-create endpoint to hand to your customers’ browsers.
Every JSON response follows the same { data, meta } envelope — data
carries the payload, meta carries the request_id and timestamp. Quote
meta.request_id when you report a bad payload; support can trace the
origin read from it.
1. Render the incident feed
GET /api/v1/public/incidents returns the platform’s declared incidents
over a look-back window (days 1–365, default 90), newest first. Filter
by component or status when your page needs a shard — a
voice-only status strip, a resolved-incidents archive.
200
{"incidents": []} — render your all-good banner
rather than branch-crashing on a null.
2. Open one incident’s timeline
GET /api/v1/public/incidents/{id} returns the same row plus its
status-update timeline (newest first, capped at the 100 most recent
updates). Follow the lifecycle as it moves
investigating → identified → monitoring → resolved — an unknown id
returns a plain 404.
200
3. Parse the RSS feed (aggregators / uptime widgets)
GET /api/v1/public/incidents.rss returns the most recent 50 incidents as
RSS 2.0 (application/rss+xml). Item titles are prefixed with the current
status — [resolved] reads as history, [investigating] as live. Treat
the feed as a convenience for readers and polling aggregators; a JSON
client should prefer the filtered list op above.
4. Subscribe a reader to incident emails
POST /api/v1/public/statuspage/subscribers starts a double-opt-in flow:
the reader (or your embedded widget) submits an email, an out-of-band
confirmation email lands, and the body answers with
status: "pending_confirmation" and HTTP 202. A repeat subscribe for an
already-confirmed address is idempotent — it answers
status: "already_subscribed" with HTTP 200 and does not re-email, so a
double-clicked widget submit is safe. The route is rate-limited per IP —
map a 429 to a retry-after backoff.
202
<api-host>/api/v1/public/statuspage/subscribers/confirm/{token} — a GET,
because email clients open links with GET. It flips the subscription to
confirmed (or answers already_confirmed on a repeat click / unknown
token, both as an idempotent success envelope).
5. Render one-click unsubscribe
Every incident notification carries a one-click unsubscribe atGET /api/v1/public/statuspage/subscribers/unsubscribe/{token}. It
returns {"status": "unsubscribed"} on the first click and keeps
returning the idempotent success {"status": "already_unsubscribed"} on
any later click — so your embedded unsubscribe page can render without
worrying about the second-tap double-debug. A fresh subscribe re-creates
the row cleanly; no manual dedupe work.
Errors worth branching on
These five failures cover the status POST (POST /api/v1/status-page/updates), which every incident flow fires. Each block below is a full{ error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.
401 — Unauthorized
401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.
403 — Forbidden
403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.
422 — Schema
422 means the payload did not match the request schema — branch on error.details.field and resend with an allowed state value instead of blind-retrying the same body.
429 — Rate
Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.