Skip to main content
Every request carries a bearer key: Authorization: Bearer <key>. Keys are created in the dashboard, shown once, and stored only as a SHA-256 hash. There is no OAuth flow, so a person creates a key and your backend uses it.

Which key to use

Most integrations need one workspace key. Reach for a tenant key when a customer or a semi-trusted service should have direct access with a single tenant’s blast radius. Ship a client key in the app; it cannot read other subscribers or send.

Selecting a tenant

A workspace key implies its workspace. Add BuzzKit-Tenant: <slug> to work inside a specific tenant, the way a Stripe platform passes Stripe-Account. Leave it off and the default tenant is used, so a single-app integration never has to think about tenants.
Tenant keys already imply their tenant and need no header. A key used against a workspace or tenant it does not belong to is a 403, always.

Scopes

Every route declares one required scope, written as resource:action: messages:send, subscribers:read, events:write, topics:*, or * for everything a key may hold. The scope each operation needs is listed on its page in the API reference. A key without it gets a 403 with the code missing_permission.
Keys can never mint keys. keys:*, invites:*, members:write, workspace:delete and tenants:secrets are session-only and cannot be granted to a key at all. A key can only ever operate the data plane it was issued for, and revoking it ends that.

Errors

Every response, success or failure, uses the same envelope:
Branch on error.code, never on error.message. Quote metadata.requestId in support requests; it is also returned as the Request-Id header.

Rotation

Create the replacement key first, move your backend over, then revoke the old one from the dashboard or with DELETE /v1/workspaces/:workspaceSlug/keys/:id. Revocation takes effect immediately in the region that served the request and within about a minute everywhere else.