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
- Create a second key with the same limits.
- Deploy it, and wait until the old key stops appearing in the request log.
- 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.