Authentication & API keys
Every request to /v1 authenticates with an API key in the Authorization header:
GET /v1/meal-analyses/mna_01j9… HTTP/1.1
Host: platform.opis.health
Authorization: Bearer opis_live_3fK9q2LmZx7A_…Keys belong to a project, not to a person, so they keep working when a team member leaves. Create, list and revoke them in the console under API keys.
Live and test keys
| Live key | Test key | |
|---|---|---|
| Format | opis_live_<prefix>_<secret> | opis_test_<prefix>_<secret> |
| Runs | The production pipeline | Deterministic fixtures (test mode) |
| Sees | Live resources only | Test resources only |
| Billed | Yes (meters identification, nutrition) | Never |
| Available | After opis activates your organization | Immediately |
A test key can never read a live resource and vice versa: the API answers 404. Use separate
webhook endpoints for each mode — events are only delivered to endpoints of the same mode.
Scopes
Scopes limit what a key can do. New keys get analyses:* and files:* by default; add the others
only where needed.
| Scope | Allows |
|---|---|
analyses:write | Create, confirm, cancel and delete meal analyses and nutrition estimates |
analyses:read | Get and list meal analyses, nutrition estimates and their events |
files:write | Upload and delete files |
files:read | Get file metadata |
usage:read | Read /v1/usage |
webhooks:manage | Manage webhook endpoints through the API |
A request without the required scope gets 403 with code forbidden.
Keep keys secret
- Server-side only. Never ship a key in a mobile app, a browser bundle or a public repository.
If your app's users confirm items, your backend proxies
POST …/confirm— the device never holds the key. - Header only. Keys in query strings end up in logs and browser history. A request that carries
a key in the query string (for example
?api_key=) is rejected with400 key_in_query_rejected, and the key is revoked automatically. - Shown once. We store only a hash of the secret. The console shows
prefix…last4afterwards; if you lose a secret, create a new key. - Leak response. If a key is pushed to a public GitHub repository, GitHub's secret scanning notifies us, the key is revoked automatically and your owners and admins are emailed.
Rotation
Rotate without downtime by overlapping two keys:
- Create a new key in the same project, with the same mode and scopes.
- Deploy it to your services.
- Watch Last used for the old key in the console stop moving.
- Revoke the old key. Revocation takes effect across our fleet within about a second.
Authentication errors
| Status | Code | Meaning |
|---|---|---|
| 400 | key_in_query_rejected | A key was sent in the query string; it has been revoked |
| 401 | unauthorized | Missing, malformed, unknown, revoked or expired key |
| 403 | forbidden | The key lacks the scope this operation needs, or the caller's IP is not on the key's allowlist |
| 403 | organization_pending | A live key was used before opis activated the organization (test keys work) |
| 403 | organization_suspended | The organization is suspended; contact opis |
Error bodies follow problem details and always carry a request_id — include it
when you contact support.
The console is separate
The developer console at /console uses Google sign-in and a session cookie, not API keys. API
keys never work against the console, and console sessions never work against /v1.