Authentication
Bearer API keys, scopes, per-number restriction, rotation.
Every request carries a Bearer token:
Authorization: Bearer sk_live_<32-char-suffix>Key format
- Prefix:
sk_live_. There is nosk_test_/ sandbox-mode key today. All keys hit production — use the verification gate and idempotency keys to iterate safely. - Suffix: 32 characters of URL-safe base64 (≈192 bits of entropy).
- Stored as SHA-256: OpenPhn never persists the full key, only the hash. If you lose a key you must rotate — there's no recovery.
The first 16 characters of the key are stored plaintext to display a
recognizable "prefix" in the dashboard (e.g. sk_live_AbC123...).
Creating a key
From the dashboard: Settings → API keys → Create key. You can also use the API:
curl -X POST https://api.openphn.com/auth/api_keys \
-H "Authorization: Bearer $EXISTING_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-batch-caller",
"scopes": ["calls:create", "calls:read", "webhooks:read"],
"number_ids": ["num_abcd1234"]
}'The response contains secret — shown once. Save it.
Scopes
Omit scopes for an "all-permissions" key (backwards compatible).
Otherwise, restrict to an explicit list:
| Scope | Endpoints |
|---|---|
calls:create | POST /v1/calls, POST /v1/calls/batch |
calls:read | GET /v1/calls, GET /v1/calls/{id}, CSV export |
webhooks:read | GET /v1/webhooks, GET .../deliveries |
webhooks:write | POST /v1/webhooks, retry, delete |
numbers:write | PATCH /v1/numbers/{id}, SMS preview |
providers:write | Twilio verify + select-number |
Requests that fall outside the key's scopes return 403.
number_ids restriction
A key can be pinned to a list of numbers. Call-creation, number-config, and SMS endpoints then reject anything targeting a different number. This is useful for multi-brand setups where each product line gets its own key.
Rotation
Keys rotate without downtime:
curl -X POST https://api.openphn.com/auth/api_keys/{key_id}/rotate \
-H "Authorization: Bearer $EXISTING_KEY"Behavior:
- A new
secretis returned. Deploy it. - The old key keeps working for a grace period (currently 24h).
- Every use of the old key during the grace period is audit-logged — migrate any missed callers.
- After the grace period, the old key is revoked.
Session tokens (dashboard only)
POST /auth/login returns a short-lived JWT for the dashboard. These are
not accepted on /v1/* endpoints — those require sk_live_*. If you
see 401 "use an API key", you're sending a session token to an API route.