Skip to main content
Every request to the OptimalDial API is authenticated by a single bearer token: an API key. There is no OAuth flow, no client/secret pair, and no JWT exchange — you mint a key in the developer panel, send it on every request, and revoke it when you’re done.

API key format

OptimalDial keys look like this:
od_live_FxXkV6bA2YqpW3LhR9zJMTnGoQ8sK4dC
  • The prefix od_live_ identifies the environment (currently only live exists).
  • The remainder is 32 URL-safe characters of cryptographic randomness (256 bits of entropy).
  • Total length is around 40 characters.
  • Keys are case-sensitive.
The full key is shown to you exactly once — at the moment you create it. We store only a SHA-256 hash, plus the first 12 characters as a non-secret display prefix (e.g. od_live_FxXk) so you can identify which key you’re holding without revealing the secret. If you lose a key you must create a new one — there is no “show key” recovery. Treat the secret like a password.

Creating an API key

  1. Sign in at app.optimaldial.com as an organization owner.
  2. Open Developers in the sidebar (admin-gated during pre-release).
  3. Click Create API key, give it a descriptive name (e.g. production-billing-pipeline), and optionally set an expires_at date.
  4. Copy the full key from the one-time reveal panel and store it in your secrets manager before closing the modal.
You can have multiple active keys per organization. Create one per integration so you can rotate or revoke them independently.

Sending the key on requests

Pass the key in the Authorization header as a Bearer token. This is the only thing that needs to change between an unauthenticated request and an authenticated one.
curl -H "Authorization: Bearer od_live_FxXkV6bA2YqpW3LhR9zJMTnGoQ8sK4dC" \
     https://api.optimaldial.com/api/v1/uploads
You do not need to send X-Organization-Id on public-API requests — the key already binds the call to the organization that minted it.

What a key gives access to

Each key is scoped to one organization and carries a static set of permissions:
ScopeLets the key…
uploads:writeCreate and cancel uploads
uploads:readList uploads, fetch upload details, generate download URLs
webhooks:manageCreate, update, delete webhook endpoints; list deliveries
Today every key is issued with all three scopes. Per-key scope selection is reserved for a future release; the field exists in responses so your client can read it forward-compatibly. A key can never be used to manage other API keys — that’s intentional, so a leaked key cannot bootstrap fresh keys on its own. Key minting and revocation flow through the in-app Developers panel only.

Rotating keys

Keys never expire automatically unless you set an expires_at value at creation. To rotate:
  1. Create a new key in the developer panel.
  2. Deploy the new key to your application (env var or secret manager).
  3. Verify with a single request that the new key works.
  4. Revoke the old key in the developer panel.
Both keys can be active simultaneously, so this is a zero-downtime swap.

Auto-revocation when a user leaves an organization

If the user who minted a key is removed from the organization (or removes themselves), every key they created for that organization is auto-revoked at the database level. This is enforced by a trigger, not by application code, so it survives bugs and outages. Practical consequence: keys should be minted by a long-lived owner account (e.g. a service-owner identity), not by an individual employee who might leave.

Authentication errors

A failed auth attempt always returns 401 Unauthorized with WWW-Authenticate: Bearer and one of:
BodyReason
{"detail":"API key required"}Missing or empty Authorization header
{"detail":"Invalid API key format"}Header is present but doesn’t start with od_live_
{"detail":"Invalid or revoked API key"}Key was revoked, expired, or doesn’t exist
{"detail":"API key creator no longer exists"}The minting user was deleted
{"detail":"Organization for this API key no longer exists"}The organization was deleted
403 Forbidden is reserved for subscription failures, not auth — see errors and rate limits.