Authentication
Create, use, rotate and revoke Ody API keys. Every request sends Authorization: Bearer ody_live_… or ody_test_….
Ody authenticates every REST and MCP request with an API key sent as a Bearer token. There is no OAuth flow today: keys are created by a workspace admin and belong to that workspace.
curl https://api.ody.co/v1/api/contacts \
-H "Authorization: Bearer ody_live_…"#Key format
| Prefix | Mode | Behaviour |
|---|---|---|
ody_live_ | Live | Everything is real: texts are sent, numbers are bought, calls are dialed |
ody_test_ | Test | Reads and writes real workspace data, but anything that spends money or reaches the outside world is simulated — see Test mode |
After the prefix comes 24 random bytes (base64url). Keys are opaque: don't parse them beyond the prefix.
#Create a key
Only workspace admins and owners can create keys.
- In the app, open Settings → Developer API (on a phone: More → Settings → Developer API).
- Enter a name — "Production server", "Zapier", "Claude" — so you can tell keys apart later.
- Choose its scopes. All are pre-selected (full access); deselect to narrow the key.
- Choose Live or Test.
- Click Create key and copy the secret from the banner: "Copy your new key now — you won't see it again."
Ody stores only a SHA-256 hash of the key. The plaintext is shown once and can never be retrieved — if you lose it, revoke it and create a new one. The key list shows a masked hint (ody_live_…WXYZ), a Test badge for test keys, the scopes, and when the key was last used.
#What a key can do
A key acts as the member who created it. Every call is checked against that member's role and the workspace's row-level security, exactly as if they clicked the same button in the app. A key can never reach another workspace.
#Errors
| Status | Code | Meaning |
|---|---|---|
401 | unauthenticated | Missing, malformed, unknown or revoked key. Don't retry — fix the configuration |
403 | permission_denied | The key is valid but lacks the scope this endpoint needs. The message names the scope |
{ "error": { "code": "permission_denied", "message": "This API key is missing the 'messages:send' scope", "requestId": "req_8c1f…" } }#Rotate and revoke
Revoking is immediate: the next request with that key gets 401. Because a key's plaintext is shown only once, rotation is:
- Create a new key with the same scopes.
- Deploy it to your service.
- Revoke the old key in Settings → Developer API.
#Keep keys safe
Anyone holding a key can act as its creator within its scopes. Never put a key in browser JavaScript, a mobile app, a public repository or a shared document.
- Store keys in a secrets manager or environment variable.
- Use one key per integration so you can revoke one without breaking the others, and so "last used" stays meaningful.
- Give each key the fewest scopes it needs — a reporting dashboard needs only
conversations:read. - Use test keys in development and CI.
#CORS
/v1/api and /v1/mcp accept requests from any origin, because they authenticate with a bearer key rather than cookies. That makes browser-based tools possible — it does not make it safe to ship a key to end users' browsers.