Authentication
Every request is authenticated with an API key sent as a bearer token.
The Authorization header
Send your key on every request:
Authorization: Bearer bbo_YOUR_KEY_HERE
There are no public data endpoints — a request without a valid key returns
401. (Only /api/health, /api/ready, and the
interactive login are reachable without a key.)
Keep keys secret. A key grants access to your org's full data view.
Store it in a secret manager or env var — never in client-side code or a
committed file. Keys are shown once at creation; if lost, ask us to rotate.
About your key
- Format:
bbo_followed by a random token. Only a hash is stored server-side; we cannot recover the raw value. - Role: API keys are
viewer(read-only) by default. - Expiry: keys may be issued with an expiry; expired or revoked keys
return
401. - Scope: what data a key can see is governed by its entitlements & tier, not its role.
Error codes
| Status | Meaning | Fix |
|---|---|---|
401 Unauthorized | Missing, malformed, expired, or revoked key. | Check the Authorization header; request a new key. |
402 Payment Required | Endpoint requires a higher tier than your plan. | Upgrade the plan for that feature. |
403 Forbidden | Your entitlements don't include this endpoint or data slice. | Ask us to widen your entitlements. |
404 Not Found | Unknown path, or a resource id that doesn't exist / isn't yours. | Check the path and id. |
422 Unprocessable | Invalid query/body params (e.g. bad range, out-of-bounds n). | Fix the parameter; see the endpoint reference. |
429 Too Many Requests | Rate limit exceeded. | Back off; honor the Retry-After header. |
Rate limits
Limits are enforced per authenticated principal:
| Scope | Limit |
|---|---|
General API (/api/*) | 600 requests / minute |
Intel Agent (/api/agent/*) | 30 requests / 5 minutes |
| Login attempts (per IP) | 10 / 5 minutes |
When you exceed a limit you get 429 with a Retry-After
header (seconds). A simple backoff:
import time, requests
def get(url, headers, **kw):
while True:
r = requests.get(url, headers=headers, **kw)
if r.status_code != 429:
return r
time.sleep(int(r.headers.get("Retry-After", "5")))
Dashboard operators sign in interactively (email + password, optional 2FA) at
the dashboard.
Programmatic access always uses a
bbo_ key as above.
Support: brianley@silversentinel.ai