> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Organizations

> List, create, update, and delete organizations. Configure the legacy single-URL webhook.

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](/api-reference/introduction)
for the full story.

## Endpoints

| Method          | Path             | Description                                 |
| --------------- | ---------------- | ------------------------------------------- |
| `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 organization name                    |
| `DELETE`        | `/v1/orgs/{id}/` | Delete the organization                     |
| `GET`           | `/v1/webhook`    | Get the single-URL webhook (see note below) |
| `PUT` / `PATCH` | `/v1/webhook`    | Set the single-URL webhook                  |

## Organization object

```json theme={null}
{
  "id": 42,
  "name": "Acme Operations",
  "role": "owner",
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
```

| Field        | Type           | Description                                                                   |
| ------------ | -------------- | ----------------------------------------------------------------------------- |
| `id`         | integer        | Server-assigned organization id                                               |
| `name`       | string         | Display name                                                                  |
| `role`       | string \| null | On list responses, the caller's role in this org (`owner`, `admin`, `member`) |
| `created_at` | timestamp      | ISO 8601 in UTC                                                               |
| `updated_at` | timestamp      | ISO 8601 in UTC                                                               |

***

## List organizations

Returns every organization the caller is a member of.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.thunderphone.com/v1/orgs/ \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  resp = requests.get(
      "https://api.thunderphone.com/v1/orgs/",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  )
  orgs = resp.json()
  ```

  ```javascript Node.js theme={null}
  const orgs = await fetch("https://api.thunderphone.com/v1/orgs/", {
    headers: { Authorization: `Bearer ${process.env.THUNDERPHONE_API_KEY}` },
  }).then((r) => r.json());
  ```
</CodeGroup>

Response is a JSON array of [Organization objects](#organization-object).

<Note>
  An API key is bound to exactly one organization, so this list almost
  always has a single entry when authenticated with `sk_live_`. The
  dashboard flow uses personal tokens and can return multiple orgs.
</Note>

***

## Create organization

<CodeGroup>
  ```bash cURL theme={null}
  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 Python theme={null}
  resp = requests.post(
      "https://api.thunderphone.com/v1/orgs/",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"name": "Acme Operations"},
  )
  org = resp.json()
  ```
</CodeGroup>

| Field  | Type   | Required | Description      |
| ------ | ------ | -------- | ---------------- |
| `name` | string | yes      | 1–120 characters |

Returns `201 Created` with the new [Organization object](#organization-object).
The creator becomes the `owner` member automatically.

***

## Get organization

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.thunderphone.com/v1/orgs/42/ \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  resp = requests.get(
      f"https://api.thunderphone.com/v1/orgs/{org_id}/",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  )
  ```
</CodeGroup>

Returns `200 OK` with an [Organization object](#organization-object), or `404` if
the caller is not a member of the requested org.

***

## Update organization

<CodeGroup>
  ```bash cURL theme={null}
  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 Python theme={null}
  resp = requests.patch(
      f"https://api.thunderphone.com/v1/orgs/{org_id}/",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"name": "Acme Ops"},
  )
  ```
</CodeGroup>

Returns `200 OK` with the updated [Organization object](#organization-object).

***

## Delete organization

<Warning>
  Destructive and irreversible. Only allowed for the `owner`. You must
  remove all other members first. A user cannot delete their only
  organization.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://api.thunderphone.com/v1/orgs/42/ \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  resp = requests.delete(
      f"https://api.thunderphone.com/v1/orgs/{org_id}/",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  )
  ```
</CodeGroup>

Returns `204 No Content`.

| Status | Condition                                                     |
| ------ | ------------------------------------------------------------- |
| `204`  | Deleted                                                       |
| `400`  | Other members still present, or this is the caller's only org |
| `403`  | Caller is not the owner                                       |

***

## Legacy single-URL webhook

<Info>
  This is the **original** webhook config: one URL receives every event
  type (`call.incoming`, `call.complete`, …). It is still supported for
  existing integrations.   New integrations should use the
  [Webhook Endpoints](/webhooks/endpoints) system (multiple URLs,
  per-endpoint secrets, event filtering) — see
  [Webhooks overview](/webhooks/overview).
</Info>

### Get webhook config

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.thunderphone.com/v1/webhook \
    -H "Authorization: Bearer sk_live_YOUR_API_KEY"
  ```

  ```python Python theme={null}
  resp = requests.get(
      "https://api.thunderphone.com/v1/webhook",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
  )
  ```
</CodeGroup>

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

```json theme={null}
{
  "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

<CodeGroup>
  ```bash cURL theme={null}
  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 Python theme={null}
  resp = requests.put(
      "https://api.thunderphone.com/v1/webhook",
      headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
      json={"url": "https://example.com/thunderphone-webhook"},
  )
  ```
</CodeGroup>

| Field | Type   | Required | Description                                                           |
| ----- | ------ | -------- | --------------------------------------------------------------------- |
| `url` | string | yes      | HTTPS 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` HMAC on inbound payloads — see
[Webhooks overview](/webhooks/overview#signature-verification).

***

## Related

<CardGroup cols={2}>
  <Card title="Members" icon="users" href="/api-reference/members">
    Manage roles and memberships within an organization.
  </Card>

  <Card title="Invites" icon="envelope" href="/api-reference/invites">
    Invite users to join your organization.
  </Card>

  <Card title="Webhooks" icon="bolt" href="/webhooks/overview">
    Subscribe to real-time events delivered as HTTP POST requests.
  </Card>

  <Card title="API Keys" icon="key" href="/api-reference/developer-api-keys">
    Rotate the `sk_live_` keys your integrations use.
  </Card>
</CardGroup>
