Skip to content

Start here

Authentication

API keys, headers and how to keep keys safe.

Every request is authenticated with an API key sent as a bearer token. Keys belong to your account rather than to a single machine, so the same key works from your laptop, your CI and your production servers.

The Authorization header

curl https://odysseyapi.tech/v1/models \  -H "Authorization: Bearer $ODYSSEY_API_KEY"

Keys start with sk-ody-. The full value is shown once, when the key is created. Odyssey keeps only the last four characters, which is what the dashboard displays.

What a key carries

  • Allowed models. A key can be limited to a list of model ids. Requests for anything else are rejected with 403.
  • A monthly spend limit. Once the key reaches it, requests are rejected until the next billing period or a higher limit.
  • An optional expiry. Useful for contractors, demos and CI, where a key should stop working on its own.

All three are set when you create a key and can be changed later.

Rotating a key

  1. Create a second key with the same limits.
  2. Deploy it, and wait until the old key stops appearing in the request log.
  3. Revoke the old key. Revocation takes effect immediately.

Filtering Activity by key shows whether anything is still using the old one.

Keeping keys safe

  • Keep keys in environment variables or a secret manager, never in source control.
  • Don't call the API from a browser or a mobile app. Anything shipped to a device can be read, so proxy through your own server.
  • Give each environment its own key, so revoking staging never takes production down.
  • Set a spend limit on every key. It is the cheapest protection against a loop in a test script.

Treat a leaked key as spent

If a key reaches a public repository or a log aggregator, revoke it. Rotating is minutes of work; an unbounded key is not.

Authentication failures

A missing, malformed or revoked key returns 401:

{  "error": {    "type": "authentication_error",    "code": "invalid_api_key",    "message": "This API key is revoked. Create a new key in the dashboard."  }}

A valid key that isn't allowed to call the requested model returns 403:

{  "error": {    "type": "permission_error",    "code": "model_not_allowed",    "message": "This key may call anthropic/claude-sonnet-5, openai/gpt-5 and google/gemini-3-pro."  }}

Neither is worth retrying. See Errors for the failures that are.