API
Status API
The Status API lets scripts and CI jobs do what the Status Pages console does: create pages and components, set a component's status by hand, post incidents and scheduled maintenance with their updates, look after subscribers, connect a custom domain and read visitor analytics. Every endpoint, with its parameters, schemas, errors and an example request, is in the Status API reference. This page shows the common tasks and the rules that apply to all of them.
Paths below are relative to https://evohub.io. Requests need an API key, sent as described in API overview, except the public page reads at the end.
Note
In the console, incidents and maintenance on a status page are run from On-Call, which publishes them for you. Use the On-Call API for that flow. The endpoints here write to the page directly, for teams that run their status page on its own.
Scopes
Each endpoint needs one scope. Give a key only the ones its job needs.
| To | Scope |
|---|---|
| List and read pages, their domain, logos and analytics | status:page:read |
| Create, change and delete pages; theme, header, layout, logos, domain, analytics settings | status:page:write |
| Read components | status:component:read |
| Add, change, reorder, rename groups of, set the status of and delete components | status:component:write |
| Read incidents | status:incident:read |
| Create incidents, post and edit their updates, write postmortems | status:incident:write |
| Read maintenance | status:maintenance:read |
| Schedule maintenance and post its updates | status:maintenance:write |
| Read subscribers | status:subscriber:read |
| Remove subscribers, change subscription settings | status:subscriber:write |
| Read the Status audit log | status:audit:read |
A key without the scope gets 403, never 401. See Errors.
Set a component's status
curl -X PATCH https://evohub.io/api/v1/components/$COMPONENT_ID/status \
-H "Authorization: Bearer $EVOHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"current_status": "degraded"}'
The status is one of operational, degraded, partial_outage, major_outage and maintenance. A component linked to an Uptime monitor (source: uptime_monitor) keeps showing its monitor's live state, whatever you set. List a page's components, with their ids, with GET /api/v1/pages/{pageID}/components.
Post an incident
curl -X POST https://evohub.io/api/v1/pages/$PAGE_ID/incidents \
-H "Authorization: Bearer $EVOHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Elevated API error rates",
"impact": "major",
"affected_component_ids": ["'"$COMPONENT_ID"'"],
"body": "We are looking into elevated error rates on the API.",
"managed_in": "status_page"
}'
impact is none, minor, major or critical; it decides how the affected components show while the incident is open. With a body, confirmed subscribers who follow an affected component, or the whole page, get an email.
Then keep the timeline going and close it:
curl -X POST https://evohub.io/api/v1/pages/$PAGE_ID/incidents/$INCIDENT_ID/updates \
-H "Authorization: Bearer $EVOHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "resolved", "body": "Error rates are back to normal."}'
Each update moves the incident to its status (investigating, identified, monitoring or resolved) and mails subscribers. Editing the incident with PATCH changes its title, impact or status without an update and without mail. After it is resolved, publish a postmortem with PUT …/incidents/{id}/postmortem and {"body": "…", "published": true}.
To record an incident that is already over, send started_at, resolved_at and resolution_body when you create it. It lands on the days it happened and mails nobody.
Schedule maintenance
curl -X POST https://evohub.io/api/v1/pages/$PAGE_ID/maintenances \
-H "Authorization: Bearer $EVOHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Database upgrade",
"body": "Expect up to five minutes of read-only mode.",
"scheduled_start": "2026-10-12T22:00:00Z",
"scheduled_end": "2026-10-13T00:00:00Z",
"affected_component_ids": ["'"$COMPONENT_ID"'"],
"managed_in": "status_page"
}'
Post in_progress and completed updates to …/maintenances/{id}/updates as the work goes. Setting the window to completed with PATCH also closes its timeline with "This maintenance has been completed."
Connect a custom domain
curl -X POST https://evohub.io/api/v1/pages/$PAGE_ID/domain \
-H "Authorization: Bearer $EVOHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "status.example.com"}'
Use a subdomain; an apex domain such as example.com is refused. Create the CNAME records the answer lists at your DNS provider, then poll GET /api/v1/pages/{pageID}/domain until status is active. See Custom domain.
Read visitor analytics
GET /api/v1/pages/{pageID}/analytics?from=2026-09-01&to=2026-09-30 returns views, visitors, feed and AI reads per day and the top routes, referrers, countries and devices. GET /api/v1/pages/analytics does the same across every page the key can see, with subscriber growth and incidents published. Download one report as CSV from …/analytics/export.csv?report=referrers.
Rules that apply everywhere
- Teams. A page belongs to the whole organization or to one team. A key sees the organization-wide pages; an organization key scoped to a team also sees that team's. A page the key cannot see, and everything under it, answers 404, as if it did not exist.
- Strict bodies. A field the endpoint does not take is refused with 400
INVALID_BODY, so a typo cannot be silently ignored. - Updates. A field you leave out keeps its value, on
PUTof a page as on everyPATCH.nullclears a nullable field. A page'sslugandteam_iddo not change throughPUT: a different value is refused withVALIDATION_ERROR. - Errors. This service answers a bad field with
VALIDATION_ERRORand the field in the message, and an unexpected failure withINTERNAL_ERROR. - Public reads.
GET /api/v1/public/pages/{pageID}(or/by-domain/{domain}) and theirfeed.rssandfeed.atomneed no key and return only what visitors see. A private page answers 404.
Related
Was this page helpful?
