Auth & scopes
The platform API authenticates with a key from your org. It comes in two forms — same org, same scopes, different runtime:
| Form | Credential | Sent as |
|---|---|---|
| Server (backend) | kld_sk_live_… | Authorization: Bearer … or X-Api-Key |
| Publishable (browser) | kld_pk_live_… | exchanged by the SDK for a short-lived session; never sent as a raw bearer |
Authorization: Bearer kld_sk_live_…
# or
X-Api-Key: kld_sk_live_…
Server keys are the bearer you send from your backend on each request. Publishable keys are for the browser: the SDK trades one for a short-lived, origin-bound session token at runtime, so the publishable key itself is never a standing credential in page source. A publishable key presented directly as a bearer is rejected — use it through the SDK. A server key is browser-blocked (no CORS) so it can't leak from a page.
Existing kld_live_… legacy keys keep working as a direct bearer in both places.
Scopes
A key carries capability scopes; each route family requires one:
| Scope | Route family | Used by |
|---|---|---|
ai | /inference-api/b2b/v1/chat/*, /retrieval/* | chat embed |
design | /inference-api/b2b/v1/design/* | editor embed |
maps | designed basemaps (tiles) | tiles embed |
By default a key is minted with all three.
401 vs 403
These are distinct on purpose:
- 401 Unauthorized — missing / invalid / revoked / expired key. Re-check the key value and that it isn't revoked.
- 403 Forbidden (
insufficient_scope) — the key is valid but lacks the scope the route needs. Mint (or re-mint) a key with the right scope.
Both fail closed: a key with no scopes is denied everywhere.
See Errors for the full status table.