Cancel a scheduled deletion
/organization/{id}/restore
Undoes `DELETE /organization/{id}` inside its 30-day window: the purge is canceled and the organization becomes writable again. Connections do NOT come back — their vault credentials were deleted at the original delete, so each has to be re-authorized by hand. Requires `org:manage`, so an Org Admin can restore and not only the Owner who could delete. No body and no step-up: the delete is the dangerous direction and the undo should not cost the caller a factor. Refuses with `409` when the organization is not currently scheduled for deletion or the window has passed, with `403 organization_blocked` when the organization is under a staff hold, and with `subscription_required` when the plan lapsed — the delete canceled the Stripe subscription, so a restore without a new one is refused rather than handed back an organization every entitlement gate would immediately lock again.
Path Parameters
Organization id (org_…).
Response Body
Whether Elaichi staff may impersonate this organization's members for support. true by default. When false, every request an impersonated session makes 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).
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.
blockedpending_deletionno_plannull
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.
Whether the CALLER may delete this organization — the org:delete permission, which only the Org Owner role holds, and never for the platform root organization. Server-computed: branch on this rather than inspecting roles. Always false where the response has no member context to compute it from — the org switcher list GET /organization (one member-context lookup per row would be a per-row round trip), the staff console, and the invite-accept response. It never overstates: trust it when true, and read GET /user/me or GET /organization/{id} (both of which compute it) when you need it for a list row.
Whether the CALLER may change this organization's own settings — the org:manage permission that PATCH /organization/{id} requires, and the organization neither staff-suspended nor in its deletion grace period. Server-computed, and false wherever can_delete is for lack of a member context; it never overstates.
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.
A sentence saying why can_require_mfa is false for a caller who can otherwise manage the organization. null otherwise.
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 for the same reasons — no member context (the org switcher list, the staff console) — plus once the window has closed. Read purge_after to tell "too late" from "not yours to undo".
Set when a deletion has been scheduled (DELETE /organization/{id}). The organization is read-only until purge_after. Null otherwise.
Organization id (org_…) — the value for X-Organization-Id.
Public URL of the logo image, or null.
Whether members must hold a second factor to act in this organization. false by default, for existing and new organizations alike. When true, a signed-in session that has not shown a second factor — no TOTP challenge at login, not a 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 staff impersonation 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 too until the person connects again. Turning it OFF only lifts that requirement: a member who set up an authenticator app of their own is still challenged for it at every non-passkey sign-in, because the factor belongs to the member and no organization setting can switch it off. Changed with PATCH /organization/{id} (org:manage, interactive session only).
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.
When a scheduled deletion becomes permanent — 30 days after deletion_scheduled_at. Null unless scheduled.
Data location fixed at creation: us/eu pin a hard jurisdiction, apac is a placement hint.
Free-form org settings. PATCH /organization/{id} REPLACES this object wholesale.
Immutable after creation.
When staff granted an indefinite trial, or null. Unlocked with no end date: no countdown, no expiry email, billing still reachable.
true
curl -X POST 'https://api.elaichi.ai/organization/<id>/restore' \
-H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
-H 'Content-Type: application/json'const response = await fetch('https://api.elaichi.ai/organization/<id>/restore', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
'Content-Type': 'application/json',
},
});
const data = await response.json();
console.log(data);import os
import requests
url = "https://api.elaichi.ai/organization/<id>/restore"
headers = {
"Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
"Content-Type": "application/json",
}
response = requests.post(url, headers=headers)
print(response.json())