# Multi-Organization REST API Access
*Issue #134 — shipped v3.17.496*
The public REST API (`/api/`) can address **multiple client organizations
through a single API key**. This is built for MSPs running a single-pane-of-glass
integration (a PSA, a custom dashboard) that needs to pull or push data across
every client without minting one key per client.
Everything here is **opt-in and backward-compatible**: keys created before this
feature — and any new key left on the default scope — behave exactly as they
did before (one key, one organization).
## Key scopes
Every API key has an **Organization Scope**, chosen when you create it under
**Settings → API Keys → Create API Key**:
| Scope | Reach |
|---|---|
| `single` *(default)* | The key's home organization only. Legacy behavior. |
| `descendants` | The home organization **plus every sub-location** beneath it in the client hierarchy (Phase 18 `Organization.parent`). |
| `all` | **Every organization the key's owner can access** — all active organizations for an MSP staff user / superuser, or the owner's active memberships for a regular org user. |
A key never grants more access than its owner already has. A broad scope only
*exposes* what the owner could already reach in the web app; it cannot escalate.
## Selecting an organization per request
All list/detail/create/update endpoints accept an optional `organization`
query parameter:
| Request | Result |
|---|---|
| *(no param)* | **`single` keys & web sessions:** the home / current org only.
**`descendants` / `all` keys:** every accessible org (single-pane default). |
| `?organization=` or `?organization=` | Narrows to that one organization. **403** if the key may not access it. |
| `?organization=all` | Every organization the key can access. |
Example — list assets across all clients, then narrow to one:
```bash
# Every client's assets in one call (key must be scope=all)
curl -H "Authorization: Bearer itdocs_live_..." \
https://your-domain.com/api/assets/
# Just one client
curl -H "Authorization: Bearer itdocs_live_..." \
"https://your-domain.com/api/assets/?organization=acme-corp"
```
## Knowing which client a row belongs to
Every resource now serializes its owning organization, so a single-pane
consumer can group rows by client:
```json
{
"id": 42,
"organization": 7,
"organization_name": "Acme Corp",
"name": "ACME-DC01",
"asset_type": "server"
}
```
`organization` is writable on create/update; `organization_name` is read-only.
## Discovering the client list
`GET /api/organizations/` returns every organization the key can address — use
it to enumerate clients before iterating:
```bash
curl -H "Authorization: Bearer itdocs_live_..." \
https://your-domain.com/api/organizations/
```
## Creating records under a specific client
On `POST`, the target organization is resolved in this order:
1. `?organization=` query parameter
2. `organization` field in the request body
3. The request's primary organization (home org for a key)
The resolved organization must be in the key's accessible set, otherwise the
request is rejected with **403** and nothing is written.
```bash
curl -X POST \
-H "Authorization: Bearer itdocs_live_..." \
-H "Content-Type: application/json" \
-d '{"name": "NEW-SW01", "asset_type": "switch"}' \
"https://your-domain.com/api/assets/?organization=42"
```
## Security notes
- Cross-organization isolation is enforced on **every** request: a key can only
ever see rows in organizations its owner is entitled to. Guessing a primary
key from another client still returns 404.
- Password reveals and OTP generation are audited against the **row's own
organization**, so multi-client access stays fully traceable.
- Scope is bounded by the owner's live permissions at request time — revoking a
user's membership immediately shrinks what their `all`-scoped keys can reach.