Authentication
poolse has two credentials. They are not interchangeable.
| Credential | Looks like | Lifetime | Acts as | Lives on |
|---|---|---|---|---|
| API key | pk_live_… | Until you revoke it | Your backend, for the whole workspace, limited by the key's scopes | Your server only |
| User token (JWT) | eyJ… | 1 hour | One end-user inside your workspace | Your app, held by the SDK |
Both go in the same header:
Authorization: Bearer <credential>
What each credential can call
API key (your backend):
POST /v1/users: create or update an end-user.POST /v1/users/:user_id/tokens: mint a user token. Needsusers:manage.GET /v1/whoami: check the key and see its workspace and scopes./v1/webhooks*: manage webhooks. Needswebhooks:admin.GET /v1/calls,GET /v1/calls/:id: call history for the workspace.GET /v1/audit_logs: the audit log. Needsaudit:read.POST /admin/v1/tokens/revoke: revoke a user token. Needstokens:admin.
User token (your app, through the SDK):
/v1/me,/v1/conversations/*,/v1/messages/*,/v1/attachments/*,/v1/devices, placing and joining calls, and the WebSocket.
Answering, declining and hanging up a call, and the reply / mark-as-read actions on a notification, can also be authorised by short-lived tokens that poolse puts in the call push or the notification, so a closed app can act without a session. See Calls and Notification actions.
A user token can only reach conversations its user is a member of. Endpoint-by-endpoint details are in the API reference.
Scopes
Scopes are set when you create the key and can't be changed later; create
a new key instead. A key with no scopes can still upsert users, call
whoami and read call history, but it cannot mint user tokens.
| Scope | Unlocks |
|---|---|
users:manage | POST /v1/users/:user_id/tokens (mint user tokens). Every integration needs this. |
tokens:admin | POST /admin/v1/tokens/revoke |
webhooks:admin | Every /v1/webhooks* endpoint |
audit:read | GET /v1/audit_logs |
A call without the required scope gets 403 forbidden with the message
Missing required scope: <scope>.
You create keys in the dashboard (API keys);
there is no API for it. New keys start with users:manage ticked; untick
it only for a key that never mints tokens. Give each deployment only the
scopes it needs.
The mint flow
App → your /api/chat-token (your own session cookie or header)
your backend → POST /v1/users/:user_id/tokens (API key)
poolse → your backend { token, token_type, expires_in, expires_at }
your backend → App { token }
App → poolse (token, on every REST call and the WebSocket)
The :user_id is poolse's id for the user (a UUID), which
POST /v1/users returns. It is not your external_id. An id that isn't
a UUID, or a user that doesn't exist, gets 404.
The mint response:
{
"token": "eyJhbGciOi…",
"token_type": "bearer",
"expires_in": 3600,
"expires_at": "2026-10-27T13:00:00Z"
}
Your token route must:
- Authenticate the caller with your own session. Only mint a token for the user who is actually signed in.
- Return a fresh token each time. The SDK caches the token in memory,
asks your
getTokenfor a new one 30 seconds before it expires, and asks again once if a request comes back401.
Minting is limited to 60 calls per minute per API key; see Limits & quotas.
Revoking a user token
Call POST /admin/v1/tokens/revoke with { "token": "<the JWT>" } and a
key that has tokens:admin. From then on, until the token would have
expired, REST calls with it get 401 token_revoked and new WebSocket
connections with it are refused. Revoking also closes every WebSocket
the user has open at that moment; connections using another, still-valid
token reconnect on their own. Use it when a user signs out or you
suspect a token leaked. Details: Users.
Blocking a user (is_blocked: true on POST /v1/users) also stops their
tokens from working on REST and the WebSocket, and closes the sockets
they have open.
Rotating an API key
- Create a new key with the same scopes.
- Deploy it to your backend.
- Revoke the old key in the dashboard.
A revoked key is refused on its next request. User tokens minted with the old key keep working until they expire (at most one hour), because a token is not tied to the key that minted it. See Token rotation.