Authentication
API keys, the read/write/admin ladder, and which accounts a key can reach.
Every request carries a key as a Bearer token:
curl "$BIDANDSCALE_URL/api/v1/accounts" \
-H "Authorization: Bearer bsk_…"Create keys in Settings → API — workspace-level for keys that reach several accounts, or inside an account's settings for one clamped to it. The key is shown once. If you lose it, revoke it and create another; there is no way to retrieve it.
Keys start with bsk_ and are for this API only. The MCP server is a separate
credential surface with no keys at all — it authenticates over OAuth 2.1, so there is nothing there to
send here.
Two dimensions
A key carries a permission scope and an account scope, independently.
Permission scope
Ranked, not orthogonal: a key satisfies a requirement when its own tier is at least as high.
| Scope | Can do |
|---|---|
read | Every GET. Also starting agent runs — a read key's run gets a restricted toolset with every write tool removed, so it can analyse but not propose. |
write | Everything above, plus proposing changes, deciding approvals, and triggering syncs and audits. |
admin | Everything above, plus changing optimization targets — which change what the system does unattended. |
A request above a key's tier gets 403, not 401. The credential is valid; the permission is not.
Account scope
| Key shape | Reaches |
|---|---|
| Account key | Exactly one account. Naming any other in a URL is a 403. |
| Workspace key, all accounts | Every account in the workspace, current and future. |
| Workspace key, chosen accounts | Only the accounts picked when the key was created. |
GET /api/v1/accounts always returns exactly what the key can reach, so it works as a discovery call
whatever the shape.
An out-of-reach account never returns a 404 that would confirm it exists — you get a 403 for accounts, and agent runs outside your reach are reported as not found.
Rotating a key
Create the new key, deploy it, then revoke the old one. Revocation takes effect on the next request.
Revoked keys keep their row so /history can still attribute past changes to them.
Handling keys
- Server-side only. There are no CORS headers; a key in a browser bundle is a key anyone can read.
- One key per consumer, so you can revoke one without taking down the rest.
- Give each key the lowest scope that works. A reporting job wants
read.