
# Create an organization

`POST /v1/organizations` · permission `organizations:write`

Creates an organization in the environment. The response carries an `ETag`. An `organization.created` event is published and the change is written to the management audit log.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `Idempotency-Key` | header | no | Optional. 16-64 characters `[A-Za-z0-9_-]`; repeating the same key with the same request returns the same response. |
| `name` | string | yes | Display name, 1-256 characters, no control characters. |
| `slug` | string | no | 3-64 characters `a-z`, `0-9` and single hyphens; unique in the environment. Derived from the name when omitted. |
| `external_id` | string \| null | no | Your own identifier, up to 255 characters; unique in the environment. `null` clears it. |
| `metadata` | object \| null | no | JSON object, at most 16 KiB, 5 levels and 100 top-level keys. Returned only by the management API. |
| `brand_color` | string \| null | no | Brand color `#RRGGBB`; stored in upper case. `null` clears it. |
| `max_memberships` | integer \| null | no | Membership cap, at least 1; `null` means unlimited. |
| `default_zoneinfo` | string \| null | no | Default IANA time zone (for example `Europe/Istanbul`), used for sign-up, invitation, JIT SSO and SCIM in the organization context when the browser or IdP supplies none. `null` clears it (the environment default applies). |

Request body:

```json
{
  "name": "Acme Corp",
  "slug": "acme",
  "external_id": "crm-4821",
  "metadata": {
    "tier": "gold"
  },
  "brand_color": "#1F6FEB"
}
```

## Response

`201 Created` with the new organization.

```json
{
  "id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "name": "Acme Corp",
  "slug": "acme",
  "external_id": "crm-4821",
  "status": "active",
  "metadata": {
    "tier": "gold"
  },
  "brand_color": "#1F6FEB",
  "max_memberships": null,
  "default_zoneinfo": null,
  "created_via": "admin_api",
  "disabled_at": null,
  "deletion_requested_at": null,
  "deletion_due_at": null,
  "created_at": "2026-10-12T09:30:00.123456Z",
  "updated_at": "2026-10-12T09:30:00.123456Z",
  "version": 1
}
```

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `unknown_field` | The body has a field that is not in the schema or is read-only (`id`, `status`…). |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 403 | `quota_exceeded` | The organization limit of the environment's plan (`organizations_per_environment_max`) is reached. |
| 409 | `slug_taken` | The slug is used by another organization. |
| 409 | `slug_reserved` | The slug is a reserved word or another organization's former slug (reserved for 90 days). |
| 409 | `external_id_taken` | The `external_id` is used by another organization. |
| 422 | `validation_failed` | A field is invalid (`name`, `slug`, `external_id`, `metadata`, `brand_color`, `max_memberships`, `default_zoneinfo`). |
| 422 | `idempotency_key_reuse` | The `Idempotency-Key` was already used with a different request. |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl -X POST "https://api.eu.keenauth.com/v1/organizations" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme Corp","slug":"acme"}'
```
