Authentication
Every /v1 request must carry an API key as a bearer token:
Authorization: Bearer sk-llm-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxKeys are created and managed in the dashboard under API Keys. There is no other authentication scheme for the public API — no query-string tokens, no cookies. Browsers cannot ambiently authenticate against /v1, which is why the gateway can safely allow cross-origin requests without credentials.
Key format
| Prefix | Kind | Notes |
|---|---|---|
sk-llm- | Standard API key | 40 base62 characters after the prefix. Created in the dashboard; long-lived until expiry, rotation or revocation. |
pg- | Playground key | Short-lived (default 1 h) key minted by the dashboard Playground. Same permissions model; you will not normally create these yourself. |
The platform stores only the SHA-256 hash of the secret plus a 12-character display prefix (e.g. sk-llm-a1b2c) so you can identify a key in lists. The full secret is shown once, at creation and rotation time. If you lose it, rotate.
Scopes and limits
Each key carries an optional set of restrictions, enforced by the gateway on every request before any provider is contacted:
| Setting | Effect when violated | Error |
|---|---|---|
allowed_models | Only the listed model ids (vendor/name) may be used; GET /v1/models is filtered to match. | 403 model_not_allowed |
allowed_modalities | Restrict to text, image, audio, video, music, embedding. | 403 modality_not_allowed |
allowed_ips | Caller IP (or X-Forwarded-For when the operator trusts the proxy) must match one of the IPv4/IPv6 addresses or CIDRs. | 403 ip_not_allowed |
expires_at | Key stops working at this instant. | 401 key_expired |
budget_daily_micro / budget_monthly_micro | Spend caps in micro-USD, evaluated on the estimated cost before the request runs (UTC calendar windows). | 402 budget_exceeded |
rate_limit_rps / rate_limit_rpm | Requests per second / per minute. | 429 rate_limited |
tokens_per_minute | Estimated tokens per minute. | 429 tokens_per_minute_exceeded |
concurrent_requests | Max simultaneous in-flight requests. | 429 concurrency_exceeded |
Limits are null (unlimited) unless set. Organization-level limits — balance, monthly spending limit, quotas — apply on top of key limits. See API Keys for how budgets interact with 402 and 429, and Rate Limits for backing off.
Key lifecycle
active ──► disabled ──► active (toggle in the dashboard; disabled keys get 401 key_disabled)
active ──► revoked (permanent; 401 key_revoked)
active ──► rotate ──► new active key (old key becomes revoked immediately)- Disable when you want to pause a key temporarily.
- Revoke when a key is retired or compromised.
- Rotate to obtain a fresh secret with the same name and limits. The new key records
rotated_from_id; the previous secret stops working at once, so deploy the new secret first if you need zero downtime — create a second key, switch traffic, then revoke the old one. - Revoked keys can be deleted from the list once you no longer need their history.
Changes propagate to the gateway in near real time (the control plane publishes key state to Redis and the gateway looks keys up by hash on every request).
Failure responses
Authentication failures use the standard error envelope:
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "Invalid API key",
"request_id": "req_01J6ZK3M9PQR7S8T9V"
}
}| HTTP | code | When |
|---|---|---|
| 401 | invalid_api_key | Header missing, malformed, or key hash not found |
| 401 | key_expired | Past expires_at |
| 401 | key_disabled | Disabled in the dashboard |
| 401 | key_revoked | Revoked or superseded by rotation |
| 403 | ip_not_allowed | IP allow-list mismatch, or the organization is suspended |
Good practice
- One key per application or environment, named accordingly, with
allowed_modelsset to what that app actually uses. - Set a monthly budget on every key that runs unattended.
- Pin production keys to your egress IPs with
allowed_ips. - Never log the
Authorizationheader. The platform itself redactssk-llm-*andpg-*values from all logs and never stores request bodies unless your organization opts in.