Skip to main content
The ThunderPhone API is a REST + JSON API. Every public endpoint accepts an Organization API key via the standard OAuth 2.0 Bearer scheme and returns JSON with UTF-8 encoding.

Base URL

All examples in this reference are rooted at that base URL. The API is versioned via the /v1 path prefix — we add new fields additively and avoid breaking changes within v1.

API keys

Create a key from the dashboard:
1

Sign in

2

Open Keys

Navigate to Settings → Keys.
3

Create key

Click Create API Key, give it a name (e.g. production, ci), and copy the sk_live_... value. The raw key is shown only once — if you lose it, revoke and create a new one.
Keep API keys secret. They carry full access to your organization’s resources. Never ship them in client-side code or commit them to version control. Publishable keys (pk_live_...) are not API keys — they are a separate, origin-restricted credential for the embeddable web widget and are not accepted by this API.
API keys are exempt from the “Require passkeys” org policy. Passkeys are a human 2FA check performed at sign-in and on session use; an sk_live_... key is a machine credential with no login session to attach a passkey check to, so it authenticates independently of that policy even when it’s enabled for your organization. This is intentional — treat key issuance and rotation as your access control for server-to-server integrations, and audit or revoke keys from Organization → Keys the same way you would rotate any other standing credential. See Create a server API key and Enterprise SSO for how the policy applies to human members.

Making a request

Send the key as a bearer token in the Authorization header. The API infers your organization from the key, so you don’t need an org id in the URL path.
Successful JSON responses use 200 OK for reads and 201 Created for writes. Deletes return 204 No Content. Errors use the standard HTTP status codes listed below.

Health check

Verify API connectivity without authentication:
Response

Dashboard access (X-ThunderPhone-Org)

The dashboard at app.thunderphone.com authenticates users with a personal session/token (one user can belong to many organizations). Those requests identify the target organization via the X-ThunderPhone-Org header:
You will normally not need this header — it exists for the dashboard code path. API integrations built against an sk_live_ key should omit it; the key already carries an org binding and the header, if present, is ignored for API-key requests.

ID format

Most core resources use 64-bit integer ids (agents, phone numbers, calls, members, organizations, publishable keys, VoIP connections). Newer resources use UUID ids — integrations, developer API keys, webhook endpoints, campaigns, knowledge bases and documents, MCP servers, provider connections, investigations, and test suites — and issue reports are addressed by a UUID trace_id. Each page states the id type in its object table. Tokens (invites, API keys) are opaque strings. Every successful write returns the persisted object including its assigned id:
Timestamps are ISO 8601 with millisecond precision in UTC.

Pagination

List endpoints return a plain JSON array by default. Endpoints that can produce very large result sets (currently calls and issue reports) accept limit and offset query parameters and return a wrapped envelope:
To page forward, add limit to the current offset on each request and stop when offset + limit >= total. See each endpoint’s page for the default and maximum limit it accepts.
Billing transactions also accept limit/offset but return a plain array without the envelope — page forward until you receive fewer rows than limit.

Errors

The API uses conventional HTTP status codes: Error responses include a JSON body with a human-readable detail message:
Error body
Field-specific validation errors (400) instead map each offending field to a list of messages, using DRF’s default format:
Validation error
Most endpoints return only detail (or the field-error map) — there is no machine-readable code field on generic errors. The exception is Billing, whose payment errors add code, retryable, and next_action fields so clients can drive recovery flows (3-D Secure, card update, retry).

Rate limiting

There is no global rate limit on the API today, and general endpoints never return 429. A small number of specific endpoints carry scoped limits — for example, invite access requests are limited to 3 per hour per user, and simulations enforce a cap on concurrently running calls. These are documented on the relevant endpoint pages and return 429 Too Many Requests when exceeded (no Retry-After header is sent). Treat write operations as non-idempotent unless the endpoint documents otherwise.

Migration from /v1/orgs/<id>/... paths

The API previously nested every resource under your organization id in the URL path — e.g. /v1/orgs/42/agents. Those URLs now return 410 Gone with a body pointing to the new flat shape:
Existing integrations only need a one-line change: remove /orgs/<id> from every URL. Your sk_live_ key is unchanged and continues to identify your organization automatically.

Next steps

Quickstart

Create your first agent, provision a number, and take a test call.

Agents

Configure voices, prompts, and tool integrations.

Calls

List, inspect, and export call history.

Webhooks

Subscribe to real-time events.