ThunderPhone 2.0 is live.Self-serve, from 2¢/min.Read the announcement

Organizations

Organizations

List, create, update, and delete the organizations that own your agents, phone numbers, and billing, including the legacy single-URL webhook configuration.

Organizations are the top-level container for every ThunderPhone resource — agents, phone numbers, calls, billing, and keys. An API key is bound to exactly one organization; the endpoints on this page are the handful that let you enumerate or manage the org resource itself.

The dashboard lets a single user belong to multiple organizations and switch between them. The API treats your key's bound org as implicit on every other page in this reference — you do not need an org id in URLs for resource operations. See Authentication for the full story.

Endpoints

MethodPathDescription
GET/v1/orgs/List organizations the caller belongs to
POST/v1/orgs/Create an organization
GET/v1/orgs/{id}/Retrieve a single organization
PATCH/v1/orgs/{id}/Update the organization's name or reporting settings
DELETE/v1/orgs/{id}/Delete the organization
GET/v1/webhookGet the single-URL webhook (see note below)
PUT / PATCH/v1/webhookSet the single-URL webhook

Organization object

{
  "id": 42,
  "name": "Acme Operations",
  "role": "owner",
  "timezone": "America/Los_Angeles",
  "business_hours": {
    "mon": [{"start": "09:00", "end": "17:00"}]
  },
  "excluded_numbers": ["+14155550199"],
  "max_concurrent_calls": 20,
  "min_seconds_between_calls_to_same_number": 10,
  "new_agent_max_call_duration_seconds": 3600,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
FieldTypeDescription
idintegerServer-assigned organization id
namestringDisplay name
rolestring | nullOn list responses, the caller's role in this org (owner, admin, member)
timezonestringIANA time zone (up to 64 characters) for call-report business hours. "" means UTC
business_hoursobjectWeekly schedule keyed by mon … sun; each day holds at most four {start, end} windows in 24-hour HH:MM, end later than start. {} means no after-hours split
excluded_numbersarrayThe organization's own test numbers (up to 50, E.164). Calls from or to them are left out of report counts and Client Portals
max_concurrent_callsintegerRead-only. Most calls this organization can have in progress at once, across inbound, outbound, web and test calls. Default 20. See Call limits
min_seconds_between_calls_to_same_numberintegerRead-only. Minimum seconds between outbound calls from this organization to the same number. Default 10; 0 means no spacing. See Call limits
new_agent_max_call_duration_secondsinteger | nullRead-only. The max_call_duration_seconds a new agent starts with when you create it without one: 3600 (one hour) unless ThunderPhone set another value for your organization; null means new agents have no per-agent limit
created_attimestampISO 8601 in UTC
updated_attimestampISO 8601 in UTC

List organizations

Returns every organization the caller is a member of.

cURL
curl https://api.thunderphone.com/v1/orgs/ \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
Python
resp = requests.get(
    "https://api.thunderphone.com/v1/orgs/",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
)
orgs = resp.json()
Node.js
const orgs = await fetch("https://api.thunderphone.com/v1/orgs/", {
  headers: { Authorization: `Bearer ${process.env.THUNDERPHONE_API_KEY}` },
}).then((r) => r.json());

Response is a JSON array of Organization objects.


Create organization

cURL
curl -X POST https://api.thunderphone.com/v1/orgs/ \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Operations"}'
Python
resp = requests.post(
    "https://api.thunderphone.com/v1/orgs/",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={"name": "Acme Operations"},
)
org = resp.json()
FieldTypeRequiredDescription
namestringyes1–120 characters

Returns 201 Created with the new Organization object. The creator becomes the owner member automatically.


Get organization

cURL
curl https://api.thunderphone.com/v1/orgs/42/ \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
Python
resp = requests.get(
    f"https://api.thunderphone.com/v1/orgs/{org_id}/",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
)

Returns 200 OK with an Organization object, or 404 if the caller is not a member of the requested org.


Update organization

cURL
curl -X PATCH https://api.thunderphone.com/v1/orgs/42/ \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Ops"}'
Python
resp = requests.patch(
    f"https://api.thunderphone.com/v1/orgs/{org_id}/",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={"name": "Acme Ops"},
)

Returns 200 OK with the updated Organization object. Owners and admins can send name, timezone, business_hours and excluded_numbers; see Organization settings for an example.


Delete organization

cURL
curl -X DELETE https://api.thunderphone.com/v1/orgs/42/ \
  -H "Authorization: Token YOUR_SESSION_TOKEN"
Python
resp = requests.delete(
    f"https://api.thunderphone.com/v1/orgs/{org_id}/",
    headers={"Authorization": "Token YOUR_SESSION_TOKEN"},
)

Returns 204 No Content.

StatusCondition
204Deleted
400Other members still present, or this is the caller's only org
403Caller is not the owner, or the request used an API key

Legacy single-URL webhook

Get webhook config

cURL
curl https://api.thunderphone.com/v1/webhook \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
Python
resp = requests.get(
    "https://api.thunderphone.com/v1/webhook",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
)

Returns 200 OK with the webhook row, or 404 if the org has not configured a webhook yet.

{
  "url": "https://example.com/thunderphone-webhook",
  "secret": "whsec_abc123...",
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}

Set webhook URL

cURL
curl -X PUT https://api.thunderphone.com/v1/webhook \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/thunderphone-webhook"}'
Python
resp = requests.put(
    "https://api.thunderphone.com/v1/webhook",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={"url": "https://example.com/thunderphone-webhook"},
)
FieldTypeRequiredDescription
urlstringyesHTTPS URL; http:// is allowed only for localhost during local dev

The secret is generated server-side and rotated only when you explicitly call PUT again. Store it in your secret manager and use it to verify the X-ThunderPhone-Signature-V2 signature on inbound requests — see Webhooks overview.