boltZharp Docs
codeDevelopers

API Reference

Everything in Zharp is an HTTP API: monitors, incidents, status pages, alerting, on-call, logs, traces and your team. This page covers what every request shares; each area has its own page with every endpoint.

Quick start

  1. 1
    Create a key

    In the dashboard, open Integrations & API → Main API keys → Create API key. Pick its scopes and expiry, optionally the addresses it may be used from, and copy it — it's shown once. Keys are on every plan.

  2. 2
    Call the API

    Every path is relative to https://api.zharp.io/api/v1, and the key goes in an Authorization header:

    export ZHARP_API_KEY=zh_live_…
    
    curl "https://api.zharp.io/api/v1/monitors?status=DOWN" \
      -H "Authorization: Bearer $ZHARP_API_KEY"

Authentication

Send the key as a bearer token: Authorization: Bearer zh_live_…. The ingestion endpoints that agents and SDKs post data to take it as X-API-KEY instead (see Logs).

  • A key belongs to one workspace and only ever acts on it — no X-Workspace-Id needed, and one sent is ignored. Another workspace's ids answer 404; another workspace's /workspaces/:id answers 403.
  • A key acts as the person who created it. Their role in the workspace limits what it can do (see Roles), and the key's scope narrows that further. If they leave, their keys stop working.
  • Some routes are for people, not keys: signing in, profiles, the list of your workspaces, accepting invitations, personal notification settings, billing, and deleting a workspace. Keys get 401 there.
  • On a key's page you can limit it to Allowed IPs, change its expiry, Roll key or Revoke it, and see its last day of requests — or do it all through the API.
info
MCP tokens (zh_mcp_) work only with the MCP server; the REST API answers 401 to them.

Scopes

A key holds one or more scopes. The strongest counts: admin includes write, and write includes read.

ScopeAllows
ReadEvery GET — except alert connections and API keys, which hold secrets.
WriteRead, plus running incidents — report, acknowledge, resolve, reopen, comment, escalate — and posting status reports and their updates.
AdminEverything: creating and changing monitors, status pages, maintenance, escalation, on-call, log sources and team; every request to alert connections and API keys.
Ingest onlySending data and nothing else: the agent, the SDKs, log ingestion. Every other request gets 403. It can't be combined with another scope — the safe key to put in a server's config or an app.

Each endpoint shows the scope it needs.

Roles and permissions

Each endpoint also shows the permission it needs from the key's owner, when it needs one. Which role holds which:

PermissionOwnerManagerMemberRead-only
monitors:view✓✓✓✓
monitors:create, :edit, :delete✓✓✓—
resources:manage✓✓✓—
logs:view, team:view, workspace:view✓✓✓✓
escalation:view, on-call:view✓✓✓✓
escalation:manage, on-call:manage, team:manage_members, team:invite✓✓——
api-keys:view, api-keys:manage✓✓✓—
team:manage_roles✓———

resources:manage covers incidents, maintenance, status pages, alert connections and monitor groups. A permission the key's owner lacks answers 403, whatever the key's scope.

Requests and responses

  • Send JSON with Content-Type: application/json; uploads are multipart/form-data. Bodies can be up to 10 MB.
  • Times are ISO 8601 in UTC, 2026-10-26T09:14:32.041Z; send them the same way. A few chart fields are epoch seconds and say so.
  • Uptime is always a percentage from 0 to 100, such as 99.95; -1 in a chart means no checks in that hour or day.
  • :id in a path is a number. PUT changes only the fields you send, except where a page says it replaces the whole thing.
  • Credentials stored in Zharp — monitor passwords, auth headers, connection secrets — come back as ••••••••. Send that value back unchanged and the stored one is kept.

A success wraps the result in data:

Success
{
  "message": "Monitors retrieved successfully",
  "data": [ … ]
}

Lists that page add meta; send page and limit to move through them. Others take limit and offset, as each page says.

A paged list
{
  "message": "Incidents retrieved successfully",
  "data": [ … ],
  "meta": { "total": 60, "page": 1, "limit": 50, "totalPages": 2 }
}

Errors

An error has a message for people and an errorCode for code:

Error
{
  "message": "This API key lacks the \"admin\" scope required for POST /monitors",
  "errorCode": "accessDenied"
}
StatuserrorCodeWhy
400validationErrorA field or parameter is missing or wrong. The message names it.
401authenticationErrorNo key, or one that's invalid, disabled, expired or revoked — or a route that's for people, not keys.
403accessDeniedThe key's scope is too low, its allowed addresses don't include you, or it's another workspace's.
403authenticationErrorThe key's owner lacks the permission the endpoint needs.
403limitExceededThe plan's limit: monitors, status pages, the fastest check interval…
404resourceNotFoundNo such thing in this workspace.
409validationErrorTaken — a slug, a domain, a name — or in conflict with something.
413—The request is too large.
429rateLimitExceededOver the key's rate limit — wait for the next minute.
429limitExceededThe workspace has sent its log allowance for the month.
500serverErrorSomething failed on our side; it's safe to retry.

Rate limits

Each key can make 1,000 requests per minute, counted in calendar minutes (UTC) across all our servers. Past that, requests get 429 until the minute turns. Sending data — logs, traces, heartbeats, pushes — doesn't count against it; logs have the monthly allowance instead.

Endpoints that need no key

EndpointAuthenticated by
GET|POST /ping/:tokenThe cron monitor's token — see Heartbeats
POST /push/:tokenThe push monitor's token
GET /status-pages/public/:slugNothing — a public page as JSON. More
POST /ingest/:provider/:tokenThe log source's token
POST /public/incidents/report/:tokenThe workspace's report link

Examples

# Is anything down?
curl "https://api.zharp.io/api/v1/monitors?status=DOWN" -H "Authorization: Bearer $ZHARP_API_KEY"

# Acknowledge an incident, then resolve it (write key)
curl -X POST "https://api.zharp.io/api/v1/incidents/481/acknowledge" -H "Authorization: Bearer $ZHARP_API_KEY"
curl -X POST "https://api.zharp.io/api/v1/incidents/481/resolve" -H "Authorization: Bearer $ZHARP_API_KEY"

# Tell visitors on your status page (write key)
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 are investigating.", "status": "INVESTIGATING", "affectedMonitorIds": [57] }'

# Create a monitor (admin key)
curl -X POST "https://api.zharp.io/api/v1/monitors" \
  -H "Authorization: Bearer $ZHARP_API_KEY" -H "Content-Type: application/json" \
  -d '{ "type": "HTTP", "name": "Homepage", "url": "https://acme.io", "interval": 300 }'

Rather not poll?

A webhook pushes every monitor and incident event to you as it happens. For logs and traces, the SDKs handle batching and retries. And the MCP server lets an AI assistant read your monitors and incidents.