boltZharp Docs
stacked_line_chartAPI Reference

Status Pages

Create and configure status pages, post status reports and updates that subscribers are e-mailed about, manage subscribers — and read any public page as JSON.

Paths are relative to https://api.zharp.io/api/v1. Reading needs a read key; posting and updating status reports needs write, like incidents; changing a page itself needs admin. Every change needs the resources:manage permission. The public endpoints need no key at all. See Authentication.

Statuses

A page shows each monitor as one of these, and one headline for the whole page:

Service statusWhen
maintenanceIn a maintenance window.
downThe monitor is down.
degradedNamed in an open status report.
operationalThe monitor is up.
pausedThe monitor is paused.
unknownNot checked yet.
overallStatusWhen
major_outageEvery service on the page is down.
partial_outageSome are down.
degradedNone down, but one is degraded, a status report is open, or an incident is ongoing.
maintenanceNone of the above, and one is in maintenance.
operationalEverything else — a page with no monitors too.

Status reports move through INVESTIGATING, IDENTIFIED, MONITORING and RESOLVED. An announcement is a report without a status — a notice, not an incident.

Pages

GET/status-pages
Scope: read
The workspace's pages, newest first, each with its live overallStatus as visitors see it right now.
Request
curl "https://api.zharp.io/api/v1/status-pages" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "Status pages retrieved successfully",
  "data": [
    {
      "id": 12,
      "workspaceId": 3,
      "slug": "acme",
      "title": "Acme Status",
      "description": null,
      "status": "PUBLIC",
      "domain": "status.acme.com",
      "domainStatus": "VERIFIED",
      "themeConfig": { "design": "Modern", … },
      "createdAt": "2026-09-01T10:00:00.000Z",
      "updatedAt": "2026-10-20T14:12:00.000Z",
      "_count": { "monitors": 2 },
      "monitors": [{ "monitorId": 41, "monitor": { "id": 41, "name": "API", "status": "UP" } }],
      "hasPassword": false,
      "overallStatus": "operational"
    }
  ]
}
GET/status-pages/:id
Scope: read
One page's settings, its monitors in order, and the DNS records for its custom domain.

domainSetup says what to put in DNS: a CNAME to cnameTarget, or — for an apex domain such as acme.com, which can't hold a CNAME — A/AAAA records for addresses.

Path parameters
id
integerrequired
The status page's id.
Request
curl "https://api.zharp.io/api/v1/status-pages/12" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "…",
  "data": {
    "id": 12,
    "slug": "acme",
    "title": "Acme Status",
    "status": "PUBLIC",
    "domain": "status.acme.com",
    "domainStatus": "VERIFIED",
    "domainCheckedAt": "2026-10-26T09:00:00.000Z",
    "domainReason": null,
    "themeConfig": { … },
    "monitors": [{ "statusPageId": 12, "monitorId": 41, "order": 0, "monitor": { "id": 41, "name": "API", "type": "HTTP", "status": "UP", … } }],
    "hasPassword": false,
    "domainSetup": { "cnameTarget": "statuspage.zharp.io", "addresses": ["203.0.113.10"], "apex": false },
    …
  }
}
Errors
  • 404No such page in this workspace.
POST/status-pages
Scope: adminPermission: resources:manage
Create a page. How many you can have depends on the plan: 1 on Free, 10 on Pro, unlimited on Business. A custom domain is checked right away; the result is in domainStatus.
Body (JSON)
title
stringrequired
1–255 characters. Shown at the top of the page.
slug
stringrequired
1–63 lowercase letters, digits and hyphens, unique across Zharp. The page lives at https://SLUG.zharp.io. A few words are reserved: www, app, api, docs, status, admin and the like.
description
string | null
A line under the title.
status
string
PUBLIC (default), PRIVATE — only your team, signed in — or PASSWORD_PROTECTED. Switching away from PASSWORD_PROTECTED forgets the password.
password
string
4–128 characters. Needed for PASSWORD_PROTECTED. Stored hashed; never returned.
domain
string | null
A custom domain such as status.acme.com. Point a CNAME at statuspage.zharp.io; the page is served there once DNS checks out (see verify). "" or null removes it.
monitorIds
integer[]
The monitors on the page, in order. On update it replaces the whole list.
themeConfig
object
Look and layout — see Theme and sections. On update it replaces the whole object.
logo
string | null
A logo URL, used when themeConfig sets none.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Acme Status",
    "slug": "acme",
    "monitorIds": [
      41,
      42
    ],
    "themeConfig": {
      "design": "Modern",
      "colorTheme": "Auto",
      "sections": [
        {
          "name": "Core",
          "resources": [
            {
              "monitorId": 41,
              "name": "API"
            },
            {
              "monitorId": 42,
              "name": "Website"
            }
          ]
        }
      ]
    }
  }'
Response
{
  "message": "Status page created successfully",
  "data": {
    "id": 12,
    "workspaceId": 3,
    "slug": "acme",
    "title": "Acme Status",
    "status": "PUBLIC",
    "domain": null,
    "domainStatus": null,
    "themeConfig": { … },
    "monitors": [{ "statusPageId": 12, "monitorId": 41, "order": 0 }, { "statusPageId": 12, "monitorId": 42, "order": 1 }],
    "hasPassword": false,
    …
  }
}
Errors
  • 400A field fails validation, a reserved slug, a domain that can't be used, a password missing for a protected page, or a monitor from outside the workspace.
  • 403The plan's status page limit is reached — errorCode is limitExceeded.
  • 409The slug is taken, or the domain is already used by another page.

Theme and sections

themeConfig sets how the page looks and how its services are grouped. Every key is optional:

KeyValues
designModern (default), Classic, Minimal
colorThemeDark (default), Light, Auto — follows the visitor's system
headerLayoutvertical (default) or horizontal
logoLight, logoDarkLogo URLs for light and dark backgrounds — upload one with POST /status-pages/logo.
logoUrlWhere clicking the logo goes.
supportUrlThe “Get in touch” link: https://… or mailto:….
sectionsGroups of services: [{ "name": "Core", "resources": [{ "monitorId": 41, "name": "API", "showHistory": true }] }]. name on a resource renames the monitor for visitors; showHistory shows its 90-day bars. A monitor must also be in monitorIds; one that's in no section is added to the last.
PUT/status-pages/:id
Scope: adminPermission: resources:manage
Change a page — send only what changes. monitorIds and themeConfig replace what was there. A new password signs out everyone who unlocked the page; a new domain is checked again.
Path parameters
id
integerrequired
The status page's id.
Request
curl -X PUT "https://api.zharp.io/api/v1/status-pages/12" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Acme System Status",
    "domain": "status.acme.com"
  }'
Response
{ "message": "Status page updated successfully", "data": { "id": 12, "title": "Acme System Status", "domain": "status.acme.com", "domainStatus": "PENDING", … } }
Errors
  • 400As for creating one.
  • 404No such page in this workspace.
  • 409The slug or domain is taken.
DELETE/status-pages/:id
Scope: adminPermission: resources:manage
Delete a page, with its subscribers and reports. Nobody is told.
Path parameters
id
integerrequired
The status page's id.
Request
curl -X DELETE "https://api.zharp.io/api/v1/status-pages/12" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "Status page deleted successfully", "data": null }
Errors
  • 404No such page in this workspace.
POST/status-pages/:id/domain/verify
Scope: adminPermission: resources:manage
Check the custom domain's DNS now. It's VERIFIED when it has a CNAME to the target or all its addresses are the target's; domainReason says what's wrong otherwise. Zharp also checks pending domains every few minutes by itself.
Path parameters
id
integerrequired
The status page's id.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/12/domain/verify" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "Domain verified",
  "data": {
    "domain": "status.acme.com",
    "domainStatus": "VERIFIED",
    "domainCheckedAt": "2026-10-26T10:02:00.000Z",
    "domainReason": null,
    "domainSetup": { "cnameTarget": "statuspage.zharp.io", "addresses": ["203.0.113.10"], "apex": false }
  }
}
Errors
  • 400The page has no custom domain.
  • 429More than 12 checks a minute for this page.
  • 404No such page in this workspace.

Status reports and announcements

A status report tells visitors about a problem and is updated until it's resolved; the services it names show as degraded meanwhile. Subscribers are e-mailed when a report is posted and with each update.

GET/status-pages/:id/announcements
Scope: read
Every report and announcement on the page, newest first, each with its updates.
Path parameters
id
integerrequired
The status page's id.
Request
curl "https://api.zharp.io/api/v1/status-pages/12/announcements" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "Announcements retrieved successfully", "data": [ {
    "id": 88,
    "statusPageId": 12,
    "title": "API latency",
    "content": "We're investigating slow responses.",
    "type": "INFO",
    "status": "INVESTIGATING",
    "affectedMonitorIds": [41],
    "resolvedAt": null,
    "scheduledFor": null,
    "createdAt": "2026-10-26T09:41:00.000Z",
    "updatedAt": "2026-10-26T09:41:00.000Z",
    "updates": [
      { "id": 301, "announcementId": 88, "status": "INVESTIGATING", "message": "We're investigating slow responses.", "createdAt": "2026-10-26T09:41:00.000Z" }
    ]
  } ] }
Errors
  • 404No such page in this workspace.
POST/status-pages/:id/announcements
Scope: writePermission: resources:manage
Post a status report — with a status — or an announcement, without one. Every confirmed subscriber is e-mailed straight away — or, with scheduledFor in the future, when that time comes; until then it's not on the page.
Path parameters
id
integerrequired
The status page's id.
Body (JSON)
title
stringrequired
1–255 characters.
content
stringrequired
The first message, up to 10,000 characters.
status
string
INVESTIGATING, IDENTIFIED, MONITORING or RESOLVED. Leave it out for an announcement.
affectedMonitorIds
integer[]
Monitors on this page that are affected; they show as degraded until it's resolved.
scheduledFor
string (ISO 8601)
When it starts, if not now — for planned work announced ahead. Subscribers are e-mailed then.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/12/announcements" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "API latency",
    "content": "We're investigating slow responses.",
    "status": "INVESTIGATING",
    "affectedMonitorIds": [
      41
    ]
  }'
Response
{ "message": "Status report created successfully", "data": {
    "id": 88,
    "statusPageId": 12,
    "title": "API latency",
    "content": "We're investigating slow responses.",
    "type": "INFO",
    "status": "INVESTIGATING",
    "affectedMonitorIds": [41],
    "resolvedAt": null,
    "scheduledFor": null,
    "createdAt": "2026-10-26T09:41:00.000Z",
    "updatedAt": "2026-10-26T09:41:00.000Z",
    "updates": [
      { "id": 301, "announcementId": 88, "status": "INVESTIGATING", "message": "We're investigating slow responses.", "createdAt": "2026-10-26T09:41:00.000Z" }
    ]
  } }
Errors
  • 400A field fails validation, or an affected monitor isn't on this page.
  • 404No such page in this workspace.
POST/status-pages/:id/announcements/:announcementId/updates
Scope: writePermission: resources:manage
Add an update to a report and move it to that status. RESOLVED closes it; any other status reopens it. Subscribers are e-mailed.
Path parameters
id
integerrequired
The status page's id.
announcementId
integerrequired
The report's id.
Body (JSON)
status
stringrequired
INVESTIGATING, IDENTIFIED, MONITORING or RESOLVED.
message
stringrequired
Up to 10,000 characters.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/12/announcements/88/updates" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "RESOLVED",
    "message": "Response times are back to normal."
  }'
Response
{ "message": "Update posted", "data": { "id": 88, "status": "RESOLVED", "resolvedAt": "2026-10-26T10:20:00.000Z", "updates": [ … ], … } }
Errors
  • 400A field fails validation.
  • 404No such page or report.
PUT/status-pages/:id/announcements/:announcementId
Scope: writePermission: resources:manage
Correct a report's title, first message or affected services. Its status and updates stay as they are, and nobody is e-mailed.
Path parameters
id
integerrequired
The status page's id.
announcementId
integerrequired
The report's id.
Body (JSON)
title
string
1–255 characters.
content
string
Up to 10,000 characters.
affectedMonitorIds
integer[]
Monitors on this page.
Request
curl -X PUT "https://api.zharp.io/api/v1/status-pages/12/announcements/88" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Slow API responses in the EU"
  }'
Response
{ "message": "Status report updated", "data": { "id": 88, "title": "Slow API responses in the EU", … } }
Errors
  • 400A field fails validation.
  • 404No such page or report.
DELETE/status-pages/:id/announcements/:announcementId
Scope: writePermission: resources:manage
Delete a report or announcement and its updates. Nobody is e-mailed.
Path parameters
id
integerrequired
The status page's id.
announcementId
integerrequired
The report's id.
Request
curl -X DELETE "https://api.zharp.io/api/v1/status-pages/12/announcements/88" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "Announcement deleted successfully", "data": null }
Errors
  • 404No such page or report.
GET/status-pages/:id/maintenance
Scope: read
The maintenance windows covering the page's monitors, from 30 days ago to a year ahead. Schedule them with POST /maintenance.
Path parameters
id
integerrequired
The status page's id.
Request
curl "https://api.zharp.io/api/v1/status-pages/12/maintenance" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "Maintenance retrieved", "data": [{ "id": 5, "name": "Database upgrade", "startTime": "…", "endTime": "…", "recurring": false, "monitors": [{ "monitorId": 41 }], … }] }
Errors
  • 404No such page in this workspace.

Subscribers

Visitors subscribe by e-mail and confirm with a link (double opt-in). Only confirmed subscribers (isActive: true) are e-mailed.

GET/status-pages/:id/subscribers
Scope: read
Every subscriber, confirmed or still pending, newest first.
Path parameters
id
integerrequired
The status page's id.
Request
curl "https://api.zharp.io/api/v1/status-pages/12/subscribers" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "Subscribers retrieved successfully",
  "data": [
    { "id": 7, "statusPageId": 12, "email": "jo@example.com", "isActive": true, "confirmedAt": "…", "confirmationSentAt": "…", "createdAt": "…", "updatedAt": "…" }
  ]
}
Errors
  • 404No such page in this workspace.
POST/status-pages/:id/subscribers/import
Scope: adminPermission: resources:manage
Invite addresses in bulk. Each new one gets a confirmation e-mail — nobody is subscribed without confirming. Confirmed addresses are left alone, and one e-mailed in the last five minutes isn't e-mailed again (alreadyInvited).
Path parameters
id
integerrequired
The status page's id.
Body (JSON)
emails
string[]required
Up to 1,000 valid addresses per request. Duplicates and invalid ones are skipped.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/12/subscribers/import" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      "jo@example.com",
      "sam@example.com"
    ]
  }'
Response
{ "message": "2 confirmation e-mails sent", "data": { "invited": 2, "alreadyInvited": 0, "alreadySubscribed": 0, "invalid": 0 } }
Errors
  • 400emails isn't a list, or holds more than 1,000.
  • 404No such page in this workspace.
DELETE/status-pages/:id/subscribers/:subscriberId
Scope: adminPermission: resources:manage
Remove a subscriber. They aren't e-mailed.
Path parameters
id
integerrequired
The status page's id.
subscriberId
integerrequired
The subscriber's id.
Request
curl -X DELETE "https://api.zharp.io/api/v1/status-pages/12/subscribers/7" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "Subscriber removed", "data": null }
Errors
  • 404No such page or subscriber.

Public pages

These need no key — they are what a status page itself calls, so you can build your own page or widget on them. A PASSWORD_PROTECTED page needs the token from unlock in an X-Status-Page-Token header; a PRIVATE page can't be read here — use GET /status-pages/:id with a key instead.

GET/status-pages/public/:slug
Scope: no key
Everything the page shows: each service's status, 90 days of history and uptime, open reports and incidents, upcoming maintenance, and the last 30 days of updates.
  • history has one entry per day: timestamp is the start of the UTC day in seconds, uptime a percentage, or -1 for a day without data.
  • Feed items (activeReports, activeIncidents, upcomingMaintenance, updates) share one shape; kind is REPORT, ANNOUNCEMENT, INCIDENT or MAINTENANCE. Incidents are worded for visitors — “API is unavailable” — with nothing internal.
  • domain is set only once the custom domain is verified.
Path parameters
slug
stringrequired
The page's slug — the acme in acme.zharp.io.
Request
curl "https://api.zharp.io/api/v1/status-pages/public/acme"
Response
{
  "message": "Status page details retrieved successfully",
  "data": {
    "id": 12,
    "slug": "acme",
    "title": "Acme Status",
    "description": null,
    "domain": "status.acme.com",
    "visibility": "PUBLIC",
    "theme": { "design": "Modern", "colorTheme": "Dark", "headerLayout": "vertical", "logoLight": "https://…", "logoDark": "https://…" },
    "showBranding": false,
    "overallStatus": "degraded",
    "sections": [
      {
        "name": "Core",
        "resources": [
          {
            "monitorId": 41,
            "name": "API",
            "status": "degraded",
            "showHistory": true,
            "history": [{ "timestamp": 1753488000, "uptime": 99.87 }, …],
            "uptime": 99.91
          }
        ]
      }
    ],
    "uptimeStats": { "24h": 100, "7d": 99.95, "30d": 99.9, "90d": 99.92 },
    "activeReports": [ {
        "kind": "REPORT",
        "id": 88,
        "title": "API latency",
        "message": "We're investigating slow responses.",
        "status": "INVESTIGATING",
        "startedAt": "2026-10-26T09:41:00.000Z",
        "endedAt": null,
        "affected": ["API"],
        "updates": [{ "id": 301, "status": "INVESTIGATING", "message": "We're investigating slow responses.", "createdAt": "2026-10-26T09:41:00.000Z" }]
      } ],
    "activeIncidents": [],
    "upcomingMaintenance": [],
    "updates": [ … ],
    "period": { "days": 30, "from": "…", "to": "…" },
    "generatedAt": "2026-10-26T10:05:00.000Z"
  }
}
Errors
  • 404No page with that slug.
  • 403The page is private, or password-protected and no valid token was sent.
GET/status-pages/public/:slug/history
Scope: no key
Every report, announcement, incident and maintenance window of the last N days, newest first.
Path parameters
slug
stringrequired
The page's slug — the acme in acme.zharp.io.
Query parameters
days
integer
1–90. Default 90.
Request
curl "https://api.zharp.io/api/v1/status-pages/public/acme/history?days=30"
Response
{ "message": "…", "data": { "title": "Acme Status", "theme": { … }, "showBranding": false, "period": { "days": 30, "from": "…", "to": "…" }, "items": [ … ] } }
Errors
  • 404No page with that slug.
  • 403Private, or locked without a token.
POST/status-pages/public/:slug/subscribe
Scope: no key
Subscribe an e-mail address. A confirmation link is sent; the answer is the same whether the address is new or already subscribed.
Path parameters
slug
stringrequired
The page's slug — the acme in acme.zharp.io.
Body (JSON)
email
stringrequired
The address to subscribe.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/public/acme/subscribe" \
  -H "Content-Type: application/json" \
  -d '{ "email": "jo@example.com" }'
Response
{ "message": "Check your inbox to confirm your subscription", "data": null }
Errors
  • 400Not a valid e-mail address.
  • 429More than 20 sign-ups from one address in an hour.
POST/status-pages/public/:slug/unlock
Scope: no key
Swap a password-protected page's password for a token, valid 7 days. Send it as X-Status-Page-Token on the public endpoints above.
Path parameters
slug
stringrequired
The page's slug — the acme in acme.zharp.io.
Body (JSON)
password
stringrequired
The page's password.
Request
curl -X POST "https://api.zharp.io/api/v1/status-pages/public/acme/unlock" \
  -H "Content-Type: application/json" \
  -d '{ "password": "…" }'
Response
{ "message": "Unlocked", "data": { "token": "eyJ…", "expiresIn": 604800 } }
Errors
  • 403Wrong password.
  • 400The page isn't password-protected.
  • 429Ten wrong tries in 15 minutes — wait a little.