Public status page API

Every published status page exposes a small, stable, public API. No auth, no rate-limit headers to negotiate — just edge-cached JSON, markdown, llms.txt, and an Atom feed. The same response is rendered into the in-page API modal in the footer of every status page, so consumers can discover everything from the page itself.

Base path: /api/status-pages/public/{slug} on happyuptime.com, or just /api, /api.md, /llms.txt, /feed.xml on a custom domain.

EndpointReturnsCache
GET /api/status-pages/public/{slug}Full JSON snapshot10s edge
GET /api/status-pages/public/{slug}/markdownMarkdown summary30s edge
GET /api/status-pages/public/{slug}/llms.txtLLM instructions30s edge
GET /api/status-pages/public/{slug}/feed.xmlAtom feed of incidents60s edge
GET /api/status-pages/public/{slug}/uptime90-day daily uptime per component30s edge

CORS: Access-Control-Allow-Origin: * on the JSON endpoint. GET-only.

JSON snapshot

GET /api/status-pages/public/{slug}

bash
curl -s https://happyuptime.com/api/status-pages/public/acme
json
{ "schema_version": 1, "generated_at": "2026-04-27T16:30:00.123Z", "page": { "id": "sp_001", "name": "Acme Status", "slug": "acme", "template": "minimal", "brand_color": "#34d399", "logo_url": "/api/status-pages/sp_001/image/...", "favicon_url": "https://acme.com/favicon.ico", "show_branding": true }, "overallStatus": "operational", "summary": { "components_total": 9, "components_operational": 9, "components_degraded": 0, "components_partial_outage": 0, "components_major_outage": 0, "components_maintenance": 0, "incidents_active": 0, "incidents_resolved_30d": 11, "uptime_90d_avg": 99.97 }, "groups": [ { "id": "grp_001", "name": "API Gateway", "description": "Edge + routing tier", "display_order": 0, "is_collapsed": false, "status": "operational", "component_ids": ["comp_001", "comp_002"] } ], "components": [ { "id": "comp_001", "name": "Web App", "description": null, "group_id": "grp_001", "display_order": 0, "show_response_time": 1, "status": "operational", "last_checked_at": "2026-04-27 16:27:43" } ], "dependencies": [ { "id": "dep_001", "service_id": "svc_aws", "name": "AWS", "category": "cloud", "status": "operational", "status_page_url": "https://status.aws.amazon.com", "icon_url": null, "active_incidents": [] } ], "incidents": [ { "id": "inc_xyz", "title": "API latency", "status": "resolved", "severity": "minor", "started_at": "2026-04-25 01:14:39", "resolved_at": "2026-04-25 01:25:54" } ], "uptime": { "comp_001": { "overall": 99.97, "days": [{ "date": "2026-04-27", "uptime": 100 }] } }, "links": { "page_path": "/status/acme", "api_path": "/status/acme/api", "markdown_path": "/status/acme/api.md", "llms_path": "/status/acme/llms.txt", "feed_path": "/status/acme/feed.xml" }}

Top-level fields

FieldTypeNotes
schema_versionintegerBumped on breaking changes. Currently 1.
generated_atISO-8601When the snapshot was assembled server-side.
pageobjectPage metadata (id, name, slug, template, brand).
overallStatusenumWorst status across all components. See values below.
summaryobjectComponent counts, active/30d incidents, 90-day uptime average.
groupsarraySubsystems with rolled-up status. Each lists its component_ids.
componentsarrayIndividual components. description is intentionally null on the public payload (descriptions can leak underlying monitor URLs).
dependenciesarrayThird-party services tracked on this page (AWS, Stripe, etc.) with current status + active provider incidents.
incidentsarrayLast 14 days, plus all currently active. Newest first.
uptimeobjectPer-component map of 90-day daily uptime + overall. Only includes components backed by a monitor.
linksobjectSibling endpoint paths (relative to the page's host).

Status values

ValueMeaning
operationalAll checks passing
degradedSome checks slow or partial failures
partial_outageSome regions failing
major_outageAll regions failing
maintenancePlanned maintenance window active
unknownComponent has a monitor but no recent results

Markdown summary

GET /api/status-pages/public/{slug}/markdown

A short, opinionated markdown rendering of the same payload — sections for Endpoints, Subsystems, Components, Dependencies, and Recent Incidents. Designed to be paste-ready into LLM prompts and to keep response size small.

LLM instructions

GET /api/status-pages/public/{slug}/llms.txt

A plain-text instruction file describing how an LLM should consume the JSON endpoint, including the schema, status enum, and read-only constraint.

Atom feed

GET /api/status-pages/public/{slug}/feed.xml

Atom 1.0 feed of the 50 most-recent incidents (active + resolved). Suitable for RSS readers, Slack RSS apps, and webhook bridges.

Code samples

javascript
const r = await fetch("https://happyuptime.com/api/status-pages/public/acme");const data = await r.json();console.log(data.overallStatus, data.summary.uptime_90d_avg);
python
import requestsr = requests.get("https://happyuptime.com/api/status-pages/public/acme")print(r.json()["overallStatus"])
bash
curl -s https://happyuptime.com/api/status-pages/public/acme | jq .summary

In-page API modal

Every rendered status page now ships an API link in the footer that opens a responsive modal (centered dialog on desktop, bottom drawer on mobile) with:

  • The full endpoint URL with one-click copy
  • cURL / JavaScript / Python tabs
  • Direct links to all sibling endpoints (markdown, llms.txt, feed.xml)
  • A collapsible response-schema preview

The modal is server-rendered into the page (no JS framework, ~3KB of inline JS

  • CSS). It does not call any external resource and works under strict CSP as long as inline <script> and <style> are allowed.

Caching

  • JSON is edge-cached for 10 seconds.
  • Markdown / llms.txt are cached for 30 seconds.
  • Atom feed is cached for 60 seconds.

If you need real-time data, use the WebSocket endpoint at /api/ws/{projectId} (authenticated; for first-party dashboards).

Compatibility

  • schema_version will only change in lock-step with breaking changes to the shape (renamed/removed fields). Additive fields do not bump it.
  • The endpoint also returns a few legacy / deprecated fields (uptimeData is exposed as uptime, status enum stays in snake_case). Use only the keys documented above.