Personal API keys act with their owner's current permissions, limited by the actions and optional workspace selected when the key is created. Manage your keys on the API keys page in organization settings. Any active member can create and revoke their own keys; administrators can also revoke members' keys.
Exchange your key
The SDKs exchange your key automatically. For direct HTTP calls, exchange it
for a five-minute access token first. This example uses jq:
export NEBULA_API_KEY="..."
export NEBULA_ACCESS_TOKEN="$(
jq -n --arg api_key "$NEBULA_API_KEY" '{api_key: $api_key}' |
curl --fail-with-body https://auth.zeroset.com/api-keys/exchange \
-H "Content-Type: application/json" --data-binary @- |
jq -er .access_token
)"
curl "https://api.zeroset.com/v2/workspaces" \
-H "Authorization: Bearer $NEBULA_ACCESS_TOKEN"Repeat the exchange when the token expires. The raw key goes only to the auth service; public API requests carry the access token.
Scope
The verified credential selects the organization. Compact URLs select a
workspace or collection; the server resolves ancestry and checks current
permissions. Unknown resources, resources in another organization, and denied
workspace actions return not_found.
Keys have immutable allowed_actions: resources:read, resources:write,
operations:manage, collections:create, and collections:manage. Choose only
the actions needed. An optional workspace limit further narrows access;
omitting it allows workspaces the owner can currently access. Discovery
requires resources:read. Keys expire within 90 days, and changing limits
requires issuing a replacement.
A suspended workspace fails with
workspace_suspended, which
shares the forbidden type. Branch on code, not type.
Revoking a key blocks new exchanges immediately. Existing tokens and open operation streams lose authorization within 30 seconds of revocation or lost owner access. Already accepted durable operations continue.
Two error surfaces
This trips people up, so it is worth stating plainly.
| Data plane | Authentication | |
|---|---|---|
| Media type | application/json | application/problem+json |
type | a bare token, e.g. conflict | an absolute URI |
| Documented at | error codes | problem codes |
Five codes appear in both — conflict, forbidden, invalid_request,
not_found, rate_limited — with different meanings. The media type tells you
which surface you are on.
Handling failures
Branch on code, which is unique, rather than type, which several codes
share. Treat code as an open enumeration and keep a default branch.
429 responses carry a Retry-After header in delta-seconds; honour it rather
than retrying immediately.