Elaichi Current user API
The Current user API from Elaichi — 1 operation(s) for current user.
The Current user API from Elaichi — 1 operation(s) for current user.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/elaichi-ai:elaichi-ai-current-user-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Elaichi Current user API
version: 0.1.0
description: 'Control-plane HTTP API for Elaichi, the MCP control plane for SaaS teams. Authenticate with an organization API token (create one in the Elaichi app under Settings → API tokens) sent as a bearer token, plus the `X-Organization-Id` header on org-scoped routes; the MCP and OAuth endpoints use their own protocols. A few actions are deliberately not available to an API token and must be done by a person in the Elaichi app: managing API and SCIM tokens, creating an organization, approving an access request, deleting an organization, and changing the two-factor requirement. The operations concerned say so. Endpoints used only by the Elaichi app itself (sign-in, consent screens, browser redirects, inbound webhooks) are not documented.'
servers:
- url: https://api.elaichi.ai
description: Production
tags:
- name: Current user
paths:
/user/me:
get:
operationId: getCurrentUser
summary: Get the current user and their organizations
tags:
- Current user
responses:
'200':
description: OK
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/User'
- type: object
properties:
mfa_enabled:
type: boolean
description: True when TOTP is active on this account.
mfa_setup_required:
type: boolean
description: True when THIS session would be refused (`403 mfa_setup_required`) in at least one organization the user belongs to, because the organization requires a second factor and the session has not shown one. Always `false` for an API token. A client routes the person to second-factor setup on this rather than working out which organizations require one.
mfa_setup_required_org_ids:
type: array
items:
type: string
description: 'The organizations behind `mfa_setup_required`: a bounded page (at most 50), with the organization named by the `current_org_id` query parameter first when it is one of them. Not the whole set — `mfa_setup_required_org_count` is the true number; an organization not listed still refuses with `403 mfa_setup_required` when entered.'
mfa_setup_required_org_count:
type: integer
minimum: 0
description: How many organizations refuse this session for lack of a second factor.
can_disable_mfa:
type: boolean
description: '`false` while an organization the user belongs to requires a second factor and they hold no passkey — turning the authenticator app off (`DELETE /user/me/mfa/totp`) is refused with `409 mfa_required_by_organization`. The reason is in `mfa_disable_blocked_reason`.'
mfa_disable_blocked_reason:
type:
- string
- 'null'
description: A sentence saying why `can_disable_mfa` is `false`, or `null`.
is_root_org_staff:
type: boolean
description: True only for Elaichi support accounts. Always false for customer members.
organizations:
type: array
description: One entry per active membership. Organizations where membership has lapsed are omitted.
items:
type: object
properties:
organization:
$ref: '#/components/schemas/Organization'
member:
type: object
description: Membership facts only — roles and teams are the sibling fields below, not nested here.
properties:
user_id:
type: string
description: User id (`usr_…`).
status:
type: string
via:
type:
- string
- 'null'
description: How they joined, e.g. invite or verified domain.
joined_at:
type: string
format: date-time
roles:
type: array
description: Role summaries held in this organization.
items:
type: object
properties:
id:
type: string
description: Role id (`role_…`).
name:
type: string
is_system:
type: boolean
seat_class:
type: string
enum:
- billable
- free_admin
teams:
type: array
items:
type: object
properties:
id:
type: string
description: Team id (`team_…`).
name:
type: string
permissions:
type: array
items:
type: string
description: Effective permission names, unioned across roles. This is the authoritative list for deciding what to show; the server re-checks it on every request.
unpaid_seat_charge:
type:
- object
- 'null'
description: 'The current organization only (`current_org_id`), and only when these permissions include `billing:view` (absent otherwise): null unless a seat-change invoice the card holder can act on is unpaid, including when the only unpaid ones are still with the bank. The newest such charge, as `unpaid_seat_charges.newest` on `GET /organization/{id}/billing`, plus `count` (every unpaid seat charge). The Elaichi app shows it as a bar on every page.'
properties:
state:
type: string
enum:
- failed
- needs_approval
- bank_approval
amount_due:
type:
- number
- 'null'
description: Major units of `currency`.
currency:
type:
- string
- 'null'
pay_url:
type:
- string
- 'null'
format: uri
description: Stripe's hosted invoice page; null for `bank_approval`.
since:
type: string
format: date-time
count:
type: integer
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: Forbidden
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: Rate limited
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
description: 'Returns the current user and their organizations. The result is the profile of whoever the credential belongs to, plus one entry per organization they are an active member of, each carrying that org''s roles, teams and effective permissions. Call this first: it is how a client learns which organization ids it may put in `X-Organization-Id` and which actions to offer. With an org API token this still returns the token owner''s memberships, so read `organizations` rather than assuming the token''s org is the only one.'
security:
- bearerAuth: []
components:
schemas:
Organization:
type: object
properties:
id:
type: string
description: Organization id (`org_…`) — the value for `X-Organization-Id`.
name:
type: string
slug:
type: string
description: Immutable after creation.
plan:
type: string
description: 'The stored plan: `personal`, `gold`, `black`, or `none` while on hold. This is not the same as the effective entitlement — read `GET /organization/{id}/entitlements` before gating a feature on it.'
region:
type:
- string
- 'null'
description: 'Data location fixed at creation: `us`/`eu` pin a hard jurisdiction, `apac` is a placement hint.'
trial_ends_at:
type:
- string
- 'null'
format: date-time
trial_indefinite_at:
type:
- string
- 'null'
format: date-time
description: '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:
type: object
additionalProperties: true
description: Free-form org settings. `PATCH /organization/{id}` REPLACES this object wholesale.
logo:
type:
- string
- 'null'
format: uri
description: Public URL of the logo image, or null.
can_delete:
type: boolean
description: '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:
type: boolean
description: '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:
type: boolean
description: 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:
type: boolean
description: '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:
type: boolean
description: '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:
type:
- string
- 'null'
description: A sentence saying why `can_require_mfa` is `false` for a caller who can otherwise manage the organization. `null` otherwise.
deletion_scheduled_at:
type:
- string
- 'null'
format: date-time
description: Set when a deletion has been scheduled (`DELETE /organization/{id}`). The organization is read-only until `purge_after`. Null otherwise.
purge_after:
type:
- string
- 'null'
format: date-time
description: When a scheduled deletion becomes permanent — 30 days after `deletion_scheduled_at`. Null unless scheduled.
can_restore:
type: boolean
description: '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:
type: boolean
description: 'Whether the CALLER may connect an app (MCP OAuth consent) to this organization right now: `false` while it is suspended, scheduled for deletion, has no active plan, or is on Personal and the caller is not its primary owner. 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:
type:
- string
- 'null'
enum:
- blocked
- pending_deletion
- no_plan
- plan_single_user
- null
description: '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`, then `plan_single_user` (Personal admits only the primary owner). `null` when connecting is open.'
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
Error:
type: object
required:
- error
description: The Elaichi error envelope. The MCP OAuth endpoints under `/oauth` are the exception — they return RFC 6749 errors instead (see `OAuthError`).
properties:
error:
type: object
required:
- message
- code
properties:
message:
type: string
description: Human-readable. 5xx messages are deliberately generic.
code:
type: string
description: Stable machine-readable code, e.g. `not_found`, `subscription_required`.
details:
description: Structured detail for codes that carry one, e.g. `toolboxes_need_resolution`.
feature:
type: string
description: The gated feature, on entitlement failures.
plan:
type:
- string
- 'null'
enum:
- personal
- gold
- black
- null
additionalProperties: true
User:
type: object
properties:
id:
type: string
description: User id (`usr_…`).
email:
type: string
format: email
name:
type:
- string
- 'null'
avatar_url:
type:
- string
- 'null'
identities:
type: array
description: Login identities linked to this account.
items:
type: object
properties:
provider:
type: string
description: e.g. `google`, `email_code`, `invite`, or an SSO connection.
connected_at:
type: string
format: date-time
is_active:
type: boolean
description: Inactive accounts cannot authenticate at all.
is_staff:
type: boolean
description: True only for Elaichi support accounts. Always false for customer members; unrelated to organization roles.
last_login_at:
type:
- string
- 'null'
format: date-time
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: session or API token
description: '`Authorization: Bearer <token>` with an org-scoped API token (`elch_{org_id}_{64 hex}`), created in the Elaichi app under Settings → API tokens. The Elaichi app itself signs in with a session cookie, which is also accepted but is not meant for integrations. Two other credential families exist and are NOT interchangeable with this one: an MCP OAuth access token (`POST /mcp` only) and a SCIM token (`/scim/v2/*` only).'
mcpOAuth:
type: oauth2
description: MCP OAuth access token, used only by `POST /mcp` — not interchangeable with `bearerAuth`. Discovered per RFC 9728/8414 at `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`.
flows:
authorizationCode:
authorizationUrl: https://api.elaichi.ai/oauth/authorize
tokenUrl: https://api.elaichi.ai/oauth/token
scopes:
mcp:read: Anything you can already see in Elaichi. Never secret values. It can also ask an admin for access to something restricted for you.
mcp:write: Create and change teams, roles, toolboxes, templates and connections, and share access.
mcp:destructive: Permanently delete data and remove access in Elaichi. This cannot be undone.
mcp:tools: Run tools from the toolboxes you choose next, deleting in your connected apps included. It can also ask an admin for access to something restricted for you.
openid: That you are signed in, and the user ID we use for you. Nothing else.
email: Your email address, and whether it is verified. Apps use this to check your domain.