Authentication
The Voka public API uses bearer API keys in the Authorization header.
Authorization: Bearer voka_live_<random>
Key format
| Prefix | Mode | Where to use |
|---|---|---|
voka_live_… | Live | Real calls, production wrappers |
voka_test_… | Test (coming soon) | Sandbox / development |
The first 12 characters (voka_live_X) are the prefix — safe to display in your own logs and dashboards. The full key is irreversibly hashed at rest; we never store it in cleartext and cannot recover it if you lose it.
Where to mint keys
In the Voka dashboard: Integrations → API Keys → Create new key.
You'll be shown the full key value once. Copy it immediately — we cannot show it again. If you lose it, rotate (creates a new value) or revoke (disables the old value).
Permission scopes
Each key gets a set of named scopes. Routes 403 when a key lacks the required scope. Adding new scopes to an existing key takes effect immediately.
| Scope | Endpoints / events it authorizes |
|---|---|
read_assistants | GET /api/v1/assistants |
read_calls | GET /api/v1/calls, GET /api/v1/calls/{id}, GET /api/v1/calls/{id}/transcript |
read_analytics | GET /api/v1/outbound-calls/{id}/transcript |
outbound_calls | POST /api/v1/outbound-calls |
manage_webhooks | POST / GET / DELETE /api/v1/webhook-subscriptions, secret rotation |
send_sms (coming soon) | POST /api/v1/sms/send |
The marketplace integration preset in the dashboard pre-checks read_assistants + read_calls + manage_webhooks — the minimum that a typical Zapier / n8n / Make wrapper needs.
Connection-test endpoint
Every wrapper validates the saved connection by calling:
GET /api/v1/auth/whoami
This requires NO scope (any valid key works). Returns the customer identity + the scopes the key actually has, so the wrapper can branch its UI based on what's enabled.
curl https://voice.vokaai.com/api/v1/auth/whoami \
-H "Authorization: Bearer voka_live_..."
{
"customer_id": "0bf91...",
"customer_name": "Acme Dental",
"mode": "live",
"permissions": { "read_calls": true, "manage_webhooks": true, ... }
}
Failure modes
All auth failures return RFC 9457 problem details with a stable code:
| Status | Code | Meaning |
|---|---|---|
| 401 | auth.missing | No Authorization header at all |
| 401 | auth.invalid | Token doesn't match the voka_live_… format |
| 401 | auth.revoked | Key was disabled in the dashboard |
| 401 | auth.expired | Key passed its expires_at |
| 403 | perm.denied | Key is valid but lacks the scope this endpoint requires |
Failed authentication attempts are logged for security monitoring. Repeated failures from a single IP or against a single key prefix may be rate-limited or blocked.
Rotation and revocation
- Rotate — generates a new value for the same key id; old value invalid after a short grace period (recommended for normal credential hygiene).
- Revoke — sets the key to
inactiveimmediately; cannot be undone (use this if you suspect compromise).
Both flows are in Integrations → API Keys in the dashboard. Wrapper integrations should detect auth.revoked and prompt the customer to re-authenticate.
Security notes
- HTTPS only. HTTP requests are rejected.
- Never put the key in a URL query parameter — it ends up in logs and Referer headers. Always use
Authorization: Bearer. - Production API traffic is restricted to a defined set of regions. If your wrapper hosts outside North America, contact support to confirm coverage.
- Outbound calling has per-key daily spend limits and country allowlists configurable in the dashboard, so a leaked key has bounded financial blast radius.