Getting started

Authentication

One credential type: a bearer API key. No cookies, no signatures, no client secrets.

The header
Authorization: Bearer ad_live_xxxxxxxxxxxxxxxxxxxxxxxx

An API key, sent as Authorization: Bearer <key>.

Keys look like ad_live_… (production traffic, real spend) or ad_test_…. Create them in the dashboard under API keys. The full value is shown exactly once, at creation — only a SHA-256 hash is stored, so a lost key cannot be recovered, only rotated. Revoking a key takes effect immediately on the next request.

Test and live keys
ad_live_…Live

Spends real credit against the account balance and counts toward its quotas. Use in production only.

ad_test_…Test

For integration work. Same request and response shapes, same error contract — so an integration proven on a test key behaves identically on a live one.

The prefix is part of the key, not a header or a query parameter — a key is self-describing, so a secret scanner and a code reviewer can both tell at a glance which one leaked.

Shown once

A key’s full value is displayed exactly once, at creation. Only its SHA-256 hash is stored, so the platform genuinely cannot show it again — not to you, and not to an operator with database access. A lost key is rotated, never recovered.

Revocation is immediate. A revoked key fails on the next request with 401 unauthorized; there is no cache to wait out and no grace period. Revoke first, investigate second — create the replacement key before you revoke the old one if you need continuity.

Create, list and revoke keys at API keys.

Scopes

A key is granted a set of scopes at creation — the capabilities it may exercise. There are exactly two, and each is enforced at authentication, so a key cannot exceed them:

chat:writePOST /v1/chat/completions

Run a model. Spends credit against the account balance.

models:readGET /v1/models

List the published catalog. Read-only.

Choose scopes when you create the key. Leaving them unselected grants full access — every scope — so an existing integration is unaffected. A call a key is not scoped for is refused with 403 insufficient_scope (permission_error in the OpenAI error shape); the response details.required_scope names the one it was missing. Narrow a key to what it does — a detection pipeline that only reads the catalog never needs to be able to spend.

Expiry

A key can be given an optional lifetime — 30, 90, or 365 days, or never — chosen at creation. A key with a lifetime stops working the moment it passes it; a key set to never expire lives until it is revoked.

An expired key is a distinct refusal. It fails with 401 key_expired, not a generic unauthorized, so your client can tell “this key aged out, rotate it” apart from a typo or a revocation. The response carries details.expired_at. There is no grace period — create the replacement before the old one lapses if you need continuity.

The dashboard shows each key’s remaining life as an expires in N days countdown, and an aged-out key as expired — so a key nearing its end is visible before it fails a request.

A key inherits its account's standing

Authentication answering “this key is real” is not the same as authorisation answering “this account may generate”. These are the credential-shaped failures, and only the first one is about the key itself:

unauthorized
HTTP 401not retryable

Missing, malformed, or revoked API key.

email_unverified
HTTP 403not retryable

The owning account has not confirmed its email address. Open the sign-in link that was mailed to it; the same key then works unchanged.

account_suspended
HTTP 403not retryable

The account is suspended and cannot start new generations.

account_restricted
HTTP 403not retryable

The account is paused pending a trust & safety review.

Where not to put it
  • Not in browser JavaScript. Anything the browser can send, a visitor can read.
  • Not in a mobile binary. Shipped is published.
  • Not in a repository, a CI log, or an error report — use an environment variable.
  • Not in a URL query string. This API takes the credential in the Authorization header only, so it never lands in an access log or a referrer.
Authentication · AdversariaLLM