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.
/workspaces/:idThe workspace and its planGET/workspaces/:id/usageWhat it uses of its planPUT/workspaces/:idRename itGET/workspaces/:id/membersList membersPOST/workspaces/:id/membersInvite peoplePUT/workspaces/:id/members/:userIdChange a roleDELETE/workspaces/:id/members/:userIdRemove someonePOST/workspaces/:id/invitations/resendResend an invitationGET/api-keysList API keysGET/api-keys/:idOne key, with its recent requestsPOST/api-keysCreate a keyPATCH/api-keys/:idRename, disable, restrictPOST/api-keys/:id/rollNew secret, same keyPOST/api-keys/:id/revokeRevoke a keyDELETE/api-keys/:idDelete a keyWorkspace
/workspaces/:idreportToken is the workspace's public “report an incident” link — see Incidents. A limit of 9999 means unlimited.
id403.curl "https://api.zharp.io/api/v1/workspaces/3" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{
"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": "…"
}
}403Another workspace's id.
/workspaces/:id/usagelogIngest.limitBytes is null when the plan has no limit. Seats count the owner.
id403.curl "https://api.zharp.io/api/v1/workspaces/3/usage" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{
"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
}
}403Another workspace's id.
/workspaces/:idid403.nameimagenull to remove it.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"
}'{ "message": "…", "data": { "id": 3, "name": "Acme Inc", "slug": "acme-inc", … } }400A field fails validation.403The key's owner doesn't own the workspace, or another workspace's id.
Members and invitations
| Role | Can |
|---|---|
OWNER | Everything, including billing, roles and deleting the workspace. |
MANAGER | Everything but billing and roles: invite and remove people, run escalation and on-call. |
MEMBER | Create and change monitors, incidents, status pages, connections and API keys. |
READ_ONLY | See everything except secrets; change nothing. |
/workspaces/:id/membersid403.keywordroleOWNER, MANAGER, MEMBER or READ_ONLY.statusACTIVE, INVITED or INACTIVE.groupIdcurl "https://api.zharp.io/api/v1/workspaces/3/members?status=ACTIVE" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{
"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" }] }
]
}400An unknown role or status.
/workspaces/:id/membersid403.emailsroleMANAGER, MEMBER (default) or READ_ONLY.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"
}'{ "message": "…", "data": [{ "id": 41, "email": "cleo@acme.io", "role": "MEMBER", "expiresAt": "2026-11-02T10:00:00.000Z" }] }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.
/workspaces/:id/members/:userIdid403.userIdroleMANAGER, MEMBER or READ_ONLY.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"
}'{ "message": "…", "data": { "userId": 14, "role": "MANAGER", … } }400The owner's role can't change.404They aren't in this workspace.
/workspaces/:id/members/:userIdid403.userIdcurl -X DELETE "https://api.zharp.io/api/v1/workspaces/3/members/14" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{ "message": "…", "data": { "id": 88 } }400The owner can't be removed.404They aren't in this workspace.
/workspaces/:id/invitations/resendid403.emailcurl -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"
}'{ "message": "…", "data": { "id": 41, "email": "cleo@acme.io", "role": "MEMBER", "expiresAt": "…" } }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.
/api-keysincludeRevokedfalse.curl "https://api.zharp.io/api/v1/api-keys" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{ "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
} ] }/api-keys/:idhealth is active, unused, expired or revoked.
idcurl "https://api.zharp.io/api/v1/api-keys/7" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{
"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": "…" }]
}
}404No such key in this workspace.
/api-keysnamescopesread, write, admin — or ingest alone. Can't be changed later.expiresInDays30, 60, 90 or 365; null never expires.allowedIps203.0.113.0/24) it may be used from, up to 100. Empty means anywhere.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"
]
}'{ "message": "API key created", "data": { "id": 7, "name": "CI deploys", …, "plainKey": "zh_live_3f9c…e1" } }400A field fails validation, oringestwith another scope.
/api-keys/:ididnameenabledfalse stops it until it's turned back on.allowedIpsexpiresAtnull for never.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
}'{ "message": "API key updated", "data": { "id": 7, "enabled": false, … } }400A revoked key can't be turned back on.404No such key in this workspace.
/api-keys/:id/rollidcurl -X POST "https://api.zharp.io/api/v1/api-keys/7/roll" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{ "message": "API key rolled. Save the new key now — it will not be shown again.", "data": { "id": 7, …, "plainKey": "zh_live_8b0a…24" } }400A revoked key can't be rolled.404No such key in this workspace.
/api-keys/:id/revokeidcurl -X POST "https://api.zharp.io/api/v1/api-keys/7/revoke" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{ "message": "API key revoked", "data": { "id": 7, "enabled": false, "revokedAt": "…", … } }404No such key in this workspace.
/api-keys/:ididcurl -X DELETE "https://api.zharp.io/api/v1/api-keys/7" \ -H "Authorization: Bearer $ZHARP_API_KEY"
{ "message": "API key deleted" }404No such key in this workspace.
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.