boltZharp Docs
groupAPI Reference

Workspace, Team & API Keys

Read the workspace and what it uses of its plan, manage its members and invitations, and create, roll and revoke API keys.

Paths are relative to https://api.zharp.io/api/v1. A key works on its own workspace only: /workspaces/:id takes that workspace's id, and deleting the workspace, signing in, profiles and billing are for people signed in to the app, never keys. See Authentication.

Workspace

GET/workspaces/:id
Scope: readPermission: workspace:view
The workspace, its owner, and its plan with every limit.

reportToken is the workspace's public “report an incident” link — see Incidents. A limit of 9999 means unlimited.

Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Request
curl "https://api.zharp.io/api/v1/workspaces/3" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "…",
  "data": {
    "id": 3,
    "name": "Acme",
    "slug": "acme",
    "image": "https://res.cloudinary.com/…",
    "ownerId": 12,
    "reportToken": "…",
    "owner": { "name": "Ada", "email": "ada@acme.io" },
    "plan": { "slug": "pro", "displayName": "Pro", … },
    "limits": { "maxMonitors": 50, "maxStatusPages": 10, "maxSeats": 10, "minCheckIntervalSeconds": 30, "maxBrowserMonitors": 10, "logRetentionDays": 30, "maxLogIngestGbPerMonth": 30, … },
    "createdAt": "…",
    "updatedAt": "…"
  }
}
Errors
  • 403Another workspace's id.
GET/workspaces/:id/usage
Scope: readPermission: workspace:view
What the workspace uses of its plan right now — monitors, user-journey monitors, status pages, seats, and logs sent this month.

logIngest.limitBytes is null when the plan has no limit. Seats count the owner.

Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Request
curl "https://api.zharp.io/api/v1/workspaces/3/usage" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "…",
  "data": {
    "plan": { "slug": "pro", "displayName": "Pro" },
    "monitors": { "used": 14, "limit": 50 },
    "browserMonitors": { "used": 1, "limit": 10 },
    "statusPages": { "used": 2, "limit": 10 },
    "seats": { "used": 4, "limit": 10 },
    "logRetentionDays": 30,
    "logIngest": { "usedBytes": 52428800, "limitBytes": 32212254720 },
    "minCheckIntervalSeconds": 30,
    "minBrowserIntervalSeconds": 300
  }
}
Errors
  • 403Another workspace's id.
PUT/workspaces/:id
Scope: admin
Rename the workspace or change its image. Only the workspace owner's keys can.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Body (JSON)
name
string
1–100 characters.
image
string | null
An image URL, or null to remove it.
Request
curl -X PUT "https://api.zharp.io/api/v1/workspaces/3" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Inc"
  }'
Response
{ "message": "…", "data": { "id": 3, "name": "Acme Inc", "slug": "acme-inc", … } }
Errors
  • 400A field fails validation.
  • 403The key's owner doesn't own the workspace, or another workspace's id.

Members and invitations

RoleCan
OWNEREverything, including billing, roles and deleting the workspace.
MANAGEREverything but billing and roles: invite and remove people, run escalation and on-call.
MEMBERCreate and change monitors, incidents, status pages, connections and API keys.
READ_ONLYSee everything except secrets; change nothing.
GET/workspaces/:id/members
Scope: readPermission: team:view
Everyone in the workspace and everyone invited, newest first, with their role and team groups.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Query parameters
keyword
string
Text in the name or e-mail.
role
string
OWNER, MANAGER, MEMBER or READ_ONLY.
status
string
ACTIVE, INVITED or INACTIVE.
groupId
integer
Only this team group's members.
Request
curl "https://api.zharp.io/api/v1/workspaces/3/members?status=ACTIVE" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "…",
  "data": [
    { "userId": 14, "email": "ben@acme.io", "name": "Ben", "photoUrl": null, "role": "MEMBER", "status": "ACTIVE", "invitedAt": "…", "joinedAt": "…", "invitedByName": "Ada", "groups": [{ "id": 2, "name": "Backend" }] }
  ]
}
Errors
  • 400An unknown role or status.
POST/workspaces/:id/members
Scope: adminPermission: team:invite
Invite people by e-mail. Each gets an invitation e-mail, valid 7 days. Only an owner's or manager's key can; the plan's seats must allow them.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Body (JSON)
emails
string[]required
At least one address, no duplicates.
role
string
MANAGER, MEMBER (default) or READ_ONLY.
Request
curl -X POST "https://api.zharp.io/api/v1/workspaces/3/members" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "emails": [
      "cleo@acme.io"
    ],
    "role": "MEMBER"
  }'
Response
{ "message": "…", "data": [{ "id": 41, "email": "cleo@acme.io", "role": "MEMBER", "expiresAt": "2026-11-02T10:00:00.000Z" }] }
Errors
  • 400Invalid or repeated addresses.
  • 403Not enough seats on the plan (seatLimitExceeded), or the key's owner can't invite.
  • 409Someone is already a member, or already invited.
PUT/workspaces/:id/members/:userId
Scope: adminPermission: team:manage_roles
Change someone's role. Only the owner's keys can.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
userId
integerrequired
The member's user id.
Body (JSON)
role
stringrequired
MANAGER, MEMBER or READ_ONLY.
Request
curl -X PUT "https://api.zharp.io/api/v1/workspaces/3/members/14" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "MANAGER"
  }'
Response
{ "message": "…", "data": { "userId": 14, "role": "MANAGER", … } }
Errors
  • 400The owner's role can't change.
  • 404They aren't in this workspace.
DELETE/workspaces/:id/members/:userId
Scope: admin
Remove someone, or cancel their invitation. They leave their team groups and on-call rotations. An owner's or manager's key can remove anyone but the owner.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
userId
integerrequired
The member's user id.
Request
curl -X DELETE "https://api.zharp.io/api/v1/workspaces/3/members/14" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "…", "data": { "id": 88 } }
Errors
  • 400The owner can't be removed.
  • 404They aren't in this workspace.
POST/workspaces/:id/invitations/resend
Scope: adminPermission: team:invite
Send an invitation again, valid another 7 days.
Path parameters
id
integerrequired
Your workspace's id — the key's own. Any other answers 403.
Body (JSON)
email
stringrequired
The invited address.
Request
curl -X POST "https://api.zharp.io/api/v1/workspaces/3/invitations/resend" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "cleo@acme.io"
  }'
Response
{ "message": "…", "data": { "id": 41, "email": "cleo@acme.io", "role": "MEMBER", "expiresAt": "…" } }
Errors
  • 404No invitation for that address.

API keys

Keys are managed with keys, too — every request here needs admin, since a key could otherwise make itself a stronger one. A key's secret is shown once, when it's created or rolled; only a fingerprint is kept.

GET/api-keys
Scope: adminPermission: api-keys:view
The workspace's keys, newest first, with each one's requests over the last day.
Query parameters
includeRevoked
boolean
Revoked keys too. Default false.
Request
curl "https://api.zharp.io/api/v1/api-keys" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "API keys retrieved", "data": [ {
    "id": 7,
    "name": "CI deploys",
    "kind": "api",
    "scopes": ["write"],
    "maskedKey": "zh_live_a1b2····9f",
    "enabled": true,
    "expiresAt": "2027-01-24T00:00:00.000Z",
    "lastUsedAt": "2026-10-26T09:58:12.000Z",
    "lastUsedIp": "203.0.113.4",
    "allowedIps": ["203.0.113.0/24"],
    "createdAt": "2026-10-26T09:00:00.000Z",
    "revokedAt": null,
    "createdBy": { "id": 12, "name": "Ada" },
    "requests24h": 182
  } ] }
GET/api-keys/:id
Scope: adminPermission: api-keys:view
One key, with its last day's stats and its 20 most recent requests.

health is active, unused, expired or revoked.

Path parameters
id
integerrequired
The API key's id.
Request
curl "https://api.zharp.io/api/v1/api-keys/7" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{
  "message": "…",
  "data": {
    "id": 7,
    "name": "CI deploys",
    …,
    "stats": { "requests24h": 182, "errors24h": 3, "lastUsedAt": "…", "health": "active" },
    "requests": [{ "method": "POST", "path": "/api/v1/incidents/481/resolve", "status": 200, "ip": "203.0.113.4", "createdAt": "…" }]
  }
}
Errors
  • 404No such key in this workspace.
POST/api-keys
Scope: adminPermission: api-keys:manage
Create a key. The answer is the only time its secret is shown.
Body (JSON)
name
stringrequired
1–100 characters.
scopes
string[]required
One or more of read, write, admin — or ingest alone. Can't be changed later.
expiresInDays
integer | null
30, 60, 90 or 365; null never expires.
allowedIps
string[]
Addresses or IPv4 ranges (203.0.113.0/24) it may be used from, up to 100. Empty means anywhere.
Request
curl -X POST "https://api.zharp.io/api/v1/api-keys" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI deploys",
    "scopes": [
      "write"
    ],
    "expiresInDays": 90,
    "allowedIps": [
      "203.0.113.0/24"
    ]
  }'
Response
{ "message": "API key created", "data": { "id": 7, "name": "CI deploys", …, "plainKey": "zh_live_3f9c…e1" } }
Errors
  • 400A field fails validation, or ingest with another scope.
PATCH/api-keys/:id
Scope: adminPermission: api-keys:manage
Rename a key, turn it off or on, replace its allowed addresses, or change when it expires. Send what changes.
Path parameters
id
integerrequired
The API key's id.
Body (JSON)
name
string
1–100 characters.
enabled
boolean
false stops it until it's turned back on.
allowedIps
string[]
Replaces the list.
expiresAt
string (ISO 8601) | null
A new expiry, or null for never.
Request
curl -X PATCH "https://api.zharp.io/api/v1/api-keys/7" \
  -H "Authorization: Bearer $ZHARP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": false
  }'
Response
{ "message": "API key updated", "data": { "id": 7, "enabled": false, … } }
Errors
  • 400A revoked key can't be turned back on.
  • 404No such key in this workspace.
POST/api-keys/:id/roll
Scope: adminPermission: api-keys:manage
Give a key a new secret, keeping its scopes, addresses and history. The old secret stops working at once.
Path parameters
id
integerrequired
The API key's id.
Request
curl -X POST "https://api.zharp.io/api/v1/api-keys/7/roll" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "API key rolled. Save the new key now — it will not be shown again.", "data": { "id": 7, …, "plainKey": "zh_live_8b0a…24" } }
Errors
  • 400A revoked key can't be rolled.
  • 404No such key in this workspace.
POST/api-keys/:id/revoke
Scope: adminPermission: api-keys:manage
Revoke a key for good. Its request history stays readable; DELETE removes it entirely.
Path parameters
id
integerrequired
The API key's id.
Request
curl -X POST "https://api.zharp.io/api/v1/api-keys/7/revoke" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "API key revoked", "data": { "id": 7, "enabled": false, "revokedAt": "…", … } }
Errors
  • 404No such key in this workspace.
DELETE/api-keys/:id
Scope: adminPermission: api-keys:manage
Delete a key and its history.
Path parameters
id
integerrequired
The API key's id.
Request
curl -X DELETE "https://api.zharp.io/api/v1/api-keys/7" \
  -H "Authorization: Bearer $ZHARP_API_KEY"
Response
{ "message": "API key deleted" }
Errors
  • 404No such key in this workspace.
warning
A key never outranks its creator

A key acts as the person who made it: their role limits it, and its scope narrows that further. If they leave the workspace, their keys stop working.