Authentication & limits
How keys work: bearer auth, scopes, IP allowlisting and rate limits.
How a key authenticates
- Bearer auth
- Send Authorization: Bearer blu_live_… (or blu_test_… for the sandbox) on every /api/v1 request. The full key is shown once at creation. Store it in a secrets manager. An app connected to a workspace by OAuth sends its bto_at_ access token the same way; an expired or revoked token answers 401 unauthorized, and the app should reconnect (its client refreshes tokens on its own). If Blueticked cannot check an OAuth token or the workspace's status right now, the call answers 503 service_unavailable: nothing was applied, so retry shortly.
- When a key is refused
- A key has no expiry unless one is set; an owner can set or move it on the key at any time. A missing or malformed Authorization header answers 401 unauthorized, and its message names the form a key takes. A refused key answers 401 unauthorized. Once its secret checks out, details.reason says why: revoked (it will not work again; create a new key), expired (its expiry date has passed; rotate it to make it work again) or workspace_inactive (its workspace is no longer active). An unknown key or a wrong secret gets no reason, so nobody without the secret can learn whether a key exists.
- Scoped keys
- Each key grants a fixed set of scopes; a missing scope returns 403 forbidden, with details.granted and details.required naming the difference. Grant only what an integration needs, and use a separate key per system. A business-restricted key reaches only the endpoints that can bound their answer to its businesses; any other answers 403 forbidden with details.business_scope restricted.
- Publishable keys
- A blu_pub_ key ships in a web page, so it works on the agent chat endpoint only, and only from the exact origins (scheme and host) you allowed on the key. Anywhere else it answers 403 forbidden: details.key_kind is publishable off the agent chat endpoint, and details.origin names the origin it was refused from. Use a secret key for everything else.
- IP allowlist
- Restrict a key to trusted IPs or IPv4/IPv6 CIDR ranges from Developers → API keys. Requests from other sources are refused with 403.
- Rate limits
- Requests are served at the lower of the key's own limit and your plan's per-minute API limit: 60/min on Starter, 120 on Growth, 300 on Business, 600 on Enterprise, 1200 on Platform, 300 on the API plan, 60 on the Sandbox. The plan's limit is shared by every key in the workspace, so minting another key does not raise it. rate_limited (429) responses carry x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset headers, always for whichever ceiling binds first, plus Retry-After: wait that many seconds, then retry. x-ratelimit-reset is the same moment as an ISO-8601 timestamp, not a number of seconds. Failed authentication is throttled separately, per calling address: past 30 failed attempts a minute with an unrecognised key prefix, a missing or malformed Authorization header or an invalid OAuth token, or 60 across every key prefix, further attempts answer 429 rate_limited with Retry-After. Wrong secrets for a recognised prefix have a separate failure budget: the higher of 30 a minute and the key's configured request limit, still subject to the shared 60-failure ceiling. Valid secrets do not consume the authentication-failure budget; their requests use the key and plan quotas.
The header
curl "https://app.blueticked.com/api/v1/channels" \
-H "Authorization: Bearer $BLUETICKED_API_KEY"Scopes
Everything a key can be allowed to do, grouped as the create-key dialog groups them.
Each endpoint in the reference names the scope it requires.
| Workspace |
|
|---|---|
| Messaging |
|
| Analytics |
|
| Contacts |
|
| Commerce |
|
| Campaigns |
|
| Templates |
|
| Channels |
|
| Flows |
|
| Automations |
|
| AI agents |
|
| Journeys |
|
| Sites |
|
| Conversations |
|
| Tickets |
|
| Tables |
|
| Suppression |
|
| Webhooks |
|
| Integrations |
|
| Billing |
|
Sends accept either the umbrella messages:send or the per-channel scope: whatsapp:send, sms:send, email:send. The per-channel one is the least-privilege choice for a single-channel integration, which is why no endpoint lists it as its required scope.