---
title: "Update organization"
method: PATCH
path: "/organization/{id}"
tags: ["Organizations"]
---

# Update organization

`PATCH /organization/{id}`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/organization/{id}`
- Auth: HTTP bearer

Updates an organization's name, settings or security options. Requires `org:manage` and an active Gold or Black subscription, except a body that sets only `allow_staff_impersonation` and/or `mfa_required`, which is accepted whatever the plan. **`settings` is replaced wholesale, not merged**: whatever object you send becomes the entire settings object, so any key you omit is deleted. Read the current organization first and send the merged result. `name` and `allow_staff_impersonation` are normal field updates, and omitting a field leaves it untouched. `mfa_required` is a sign-in policy with its own rules: changing it needs an interactive browser session (an org API token answers 403, and the AI surfaces do not accept the field at all), it is refused to an Elaichi support session, turning it off needs step-up reauthentication in the app (`428 step_up_required`), and turning it on answers `409 mfa_setup_required` when the caller's own session would fail the check; see `can_require_mfa` on the response. A change is recorded in the `organization.updated` audit entry, with the old and new value in its `mfa_required` metadata. `slug`, `plan` and `region` cannot be changed here.

## Path parameters

- `id` string, required

## Request body

- object
  - `name` string
  - `settings` object: Replaces the stored settings object entirely. Omitted keys are lost.
  - `allow_staff_impersonation` boolean: `false` refuses Elaichi support access to this organization: every request made through a support session is refused, reads included. Recorded in the `organization.updated` audit entry: the field is named in `fields` and the value it was set to is in the entry's `allow_staff_impersonation` metadata.
  - `mfa_required` boolean: `true` requires every member to hold a second factor to act in this organization; `false` lifts it. See the operation description for who may change it and what a change needs.

## Response `200`

OK

- Organization
  - `id` string: Organization id (`org_…`) — the value for `X-Organization-Id`.
  - `name` string
  - `slug` string: Immutable after creation.
  - `plan` string: The stored plan: `gold`, `black`, or `none` when locked. This is not the same as the effective entitlement — read `GET /organization/{id}/entitlements` before gating a feature on it.
  - `region` string, nullable: Data location fixed at creation: `us`/`eu` pin a hard jurisdiction, `apac` is a placement hint.
  - `trial_ends_at` string, date-time, nullable
  - `trial_indefinite_at` string, date-time, nullable: Set when Elaichi granted this organization an indefinite trial, otherwise null. Unlocked with no end date: no countdown, no expiry email, billing still reachable.
  - `settings` object: Free-form org settings. `PATCH /organization/{id}` REPLACES this object wholesale.
  - `logo` string, uri, nullable: Public URL of the logo image, or null.
  - `can_delete` boolean: Whether the caller may delete this organization: the `org:delete` permission, which only the Org Owner role holds. Server-computed, so branch on this rather than inspecting roles. Always `false` on rows that have no member context to compute it from, such as the organization list `GET /organization`. It never overstates: trust it when true, and read `GET /user/me` or `GET /organization/{id}` (both compute it) when you need it for a list row.
  - `can_manage` boolean: Whether the caller may change this organization's settings: the `org:manage` permission that `PATCH /organization/{id}` requires, and the organization is neither suspended nor in its deletion grace period. Server-computed, and `false` wherever `can_delete` is false for lack of a member context; it never overstates.
  - `allow_staff_impersonation` boolean: Whether Elaichi support may sign in as this organization's members to help them. `true` by default. When `false`, every request made through such a support session against this organization is refused with `403 staff_impersonation_blocked`, reads included, and the organization is left out of that session's `GET /user/me` and `GET /organization`. Changed with `PATCH /organization/{id}` (`org:manage`).
  - `mfa_required` boolean: Whether members must hold a second factor to act in this organization. `false` by default. When `true`, a signed-in session that has not shown a second factor (no TOTP challenge at login, no passkey sign-in, no factor enrolled since) is refused on every organization-scoped route, reads included, with `403 mfa_setup_required`; `error.details.has_second_factor` says whether the person already has one and only needs to sign in with it. Exempt: org API tokens, Elaichi support sessions, and a session signed in through this organization's own SSO connection. MCP connections made before it was switched on, or from a session without a factor, are refused until the person connects again. Turning it off only lifts the organization requirement: a member who set up an authenticator app of their own is still challenged for it at every non-passkey sign-in. Changed with `PATCH /organization/{id}` (`org:manage`, interactive session only).
  - `can_require_mfa` boolean: Whether the CALLER may turn `mfa_required` ON right now: `can_manage`, from an interactive session that would itself pass the check it is about to create. `false` — with the reason in `can_require_mfa_reason` — when switching it on would lock the caller out of this organization. The PATCH refuses that regardless with `409 mfa_setup_required`. Turning it OFF is not governed by this field; it needs a step-up.
  - `can_require_mfa_reason` string, nullable: A sentence saying why `can_require_mfa` is `false` for a caller who can otherwise manage the organization. `null` otherwise.
  - `deletion_scheduled_at` string, date-time, nullable: Set when a deletion has been scheduled (`DELETE /organization/{id}`). The organization is read-only until `purge_after`. Null otherwise.
  - `purge_after` string, date-time, nullable: When a scheduled deletion becomes permanent — 30 days after `deletion_scheduled_at`. Null unless scheduled.
  - `can_restore` boolean: Whether the caller may cancel a scheduled deletion: the `org:manage` permission, and only while `purge_after` is still ahead. Server-computed like `can_delete`, and `false` on rows with no member context. Read `purge_after` to tell "too late" from "not yours to undo".
  - `can_authorize_apps` boolean: Whether the CALLER may connect an app (MCP OAuth consent) to this organization right now: `false` while it is suspended, scheduled for deletion, or has no active plan. Server-computed by the same gate `POST /oauth/authorize-request/{id}/approve` calls; present only on member-scoped responses. `authorize_apps_blocked_reason` says which.
  - `authorize_apps_blocked_reason` 'blocked' | 'pending_deletion' | 'no_plan' | 'null', nullable: Why `can_authorize_apps` is `false`, in the gate's own order: `blocked`, then `pending_deletion` (even when the subscription is also gone, since a soft delete cancels it), then `no_plan`. `null` when connecting is open.
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
