Concepts
Organizations
Section titled “Organizations”Everything in AirFone belongs to an organization: numbers, assistants, contacts, calls. Keys act for one organization.
A developer account can exist without one. When you sign up you get a sandbox organization of your own. A business can invite you into its organization, and you can publish connectors that any organization installs.
Test and live mode
Section titled “Test and live mode”Every organization has test and live data, kept apart. Test keys contain _test_, live keys contain _live_.
In test mode:
- Calls are simulated. No phone rings, and a scripted caller talks to your assistant.
- WhatsApp and SMS go to a simulated inbox you can see in the console.
- AI usage comes from a free test quota.
- Webhooks fire exactly as in live mode, with
"livemode": false.
| Key | Prefix | Where it lives | What it can do |
|---|---|---|---|
| Secret | af_sk_ |
Your server only | Everything the organization allows |
| Restricted | af_rk_ |
Your server, or a service you trust less | Only the scopes you pick |
| Publishable | af_pk_ |
Web pages and apps | Open widget sessions on the domains you list |
Send a secret or restricted key as Authorization: Bearer af_sk_.... A secret key is shown once when created. If one leaks, roll it in the console: the old key keeps working for the grace period you pick (none, 1 hour or 24 hours), then stops.
Scopes
Section titled “Scopes”Restricted keys carry scopes in the form resource:read or resource:write. Write includes read.
calls, messages, agents, contacts, records, webhooks, events, usage, connectors.
A call without the scope it needs gets 403 with code missing_scope, and the error names the scope.
Idempotency
Section titled “Idempotency”Send Idempotency-Key on every POST. If a request times out, send it again with the same key and you get the first result instead of a second call or message. Keys are kept for 24 hours. Reusing a key with a different body returns 409 idempotency_key_reused.
Versions
Section titled “Versions”The API is versioned by date. Your account is pinned to the version current when you made your first request. Send AirFone-Version: 2026-10-04 to choose one per request. Breaking changes only ever arrive in a new version, and every response includes the version that served it.
Errors
Section titled “Errors”Every error has the same shape:
{ "error": { "type": "invalid_request", "code": "parameter_missing", "message": "to is required.", "param": "to", "request_id": "req_4Hk2b9" }}| Status | type |
Meaning |
|---|---|---|
| 400 | invalid_request |
Something in the request is wrong. param says what. |
| 401 | authentication |
Missing, wrong or revoked key. |
| 403 | permission |
The key lacks a scope, or the domain is not allowed. |
| 404 | not_found |
No such object, or it belongs to another organization or mode. |
| 409 | conflict |
Idempotency key reused, or the object changed state. |
| 422 | unprocessable |
Valid request the platform cannot do, such as WhatsApp outside the window. |
| 429 | rate_limit |
Too many requests. Wait for Retry-After seconds. |
| 5xx | api_error |
Our fault. Safe to retry with the same idempotency key. |
Rate limits
Section titled “Rate limits”Limits are per key: 100 requests a second in live mode, 25 in test mode, with short bursts allowed. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Publishable keys are also limited per visitor IP.
Request ids
Section titled “Request ids”Every response has an AirFone-Request-Id header, and every error repeats it as request_id. Look it up under Logs in the console, and include it when you contact support.