Authentication

By Orqestra · Published September 2, 2026

Bearer tokens

Developers → API Access, listing API tokens with their prefix, scope, creation date and last use
Developers → API Access. “Create token” issues a new one; the full value is shown once.

Every request carries a token in the Authorization header. Create one under Settings → API Access in the dashboard. The full value is shown once — copy it then.

Authorization: Bearer wa_pk_xxxxxxxxxxxxxxxxxxxxxxxx

A token is scoped to one organization. There is no account-level token, and no way to reach a second organization with the same credential.

Keeping tokens safe

A token reads and writes your customers' conversations. Treat it exactly as you would a password:

  • Keep it server-side. Never ship one in frontend JavaScript, a mobile binary, or a public repository.
  • Give each integration its own token, so you can revoke one without breaking the others.
  • Set an expiry where you can, and rotate on a schedule.
  • Revoke immediately if a token is exposed — deactivation takes effect on the next request.

Permissions

Authenticating is not the same as being allowed. Each route additionally requires a named permission on the token, and the mapping is centralised in one matrix. A route with no entry in that matrix fails closed with 500 rather than quietly allowing the request — so a newly added endpoint cannot accidentally ship as authentication-only.

Grant the narrowest set that does the job. A token that only sends order updates needs chats.reply and nothing else.

PermissionGrants
broadcasts.send1 endpoint — POST /broadcasts
broadcasts.view3 endpoints — GET /broadcasts, GET /broadcasts/{id}, GET /broadcasts/csv-template
chats.assign4 endpoints — POST /chats/{id}/escalate, POST /chats/{id}/de-escalate, POST /chats/session, POST /chats/{id}/assign
chats.reply1 endpoint — POST /messages
chats.view4 endpoints — GET /chats, GET /chats/{id}, GET /chats/session, GET /chats/{id}/messages
contacts.edit9 endpoints — POST /contacts, POST /contacts/import, PATCH /contacts/{id}, POST /segments, …
contacts.view9 endpoints — GET /contacts, GET /contacts/export, GET /contacts/import-template, GET /contacts/imports, …
flows.manage1 endpoint — POST /flows/trigger
flows.view1 endpoint — GET /flows
settings.view3 endpoints — GET /channels, GET /channels/{id}, GET /organization
templates.manage3 endpoints — POST /templates, POST /templates/sync, DELETE /templates/{id}
templates.view1 endpoint — GET /templates
ticket_notes.manage1 endpoint — POST /tickets/{id}/notes
tickets.manage2 endpoints — POST /tickets, PUT /tickets/{id}
tickets.view2 endpoints — GET /tickets, GET /tickets/{id}
users.manage1 endpoint — GET /users

What failures look like

StatusCause
401No Authorization header, or the token is not recognised.
403The token is real but inactive, expired, or lacks the required permission. The message names the permission.

The split is deliberate: 401 means "who are you", 403 means "I know who you are and the answer is no". A token that stops working with 403 was revoked or expired — reissue it rather than debugging the header.