Elaichi Audit log API
The Audit log API from Elaichi — 1 operation(s) for audit log.
The Audit log API from Elaichi — 1 operation(s) for audit log.
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-audit-log-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 Audit log 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: Audit Log
paths:
/audit-log:
get:
operationId: listAuditLog
summary: List audit log events
tags:
- Audit Log
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required:
- result
- next_cursor
- prev_cursor
properties:
result:
type: array
items:
type: object
properties:
id:
type: string
description: Audit entry id (`aud_…`).
actor_user_id:
type:
- string
- 'null'
description: Null for system-generated entries (`usr_…` otherwise).
action:
type: string
description: Dotted action name, e.g. `connection.deleted`.
resource_type:
type:
- string
- 'null'
resource_id:
type:
- string
- 'null'
description: Prefixed id of the affected resource, when there is one.
metadata:
type: object
additionalProperties: true
description: Action-specific detail; shape varies by action.
created_at:
type: string
format: date-time
category:
type: string
action_kind:
type: string
actor_kind:
type: string
enum:
- user
- system
- staff
- scim
- api_token
- ai_assistant
- automation
description: '`staff` means Elaichi support did it: either directly (a `staff.*` action, where `actor_user_id` is the support user, not a member) or while signed in as a member (`actor` is the member and `metadata.impersonated_by_user_id` is the support user).'
actor:
type: object
description: The person behind this row. Read this rather than resolving `actor_user_id` against the member directory, which is paginated and would only name the actors on the page you happened to fetch.
properties:
user_id:
type:
- string
- 'null'
name:
type:
- string
- 'null'
description: Null (with `email`) when the id is no longer resolvable in this organization — a departed member, which clients render as "Former member".
email:
type:
- string
- 'null'
avatar_url:
type:
- string
- 'null'
description: 'The person''s picture: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.'
kind:
type: string
description: Mirrors `actor_kind`, so a non-human actor stays distinguishable from an unnamed one.
tool_call:
type:
- object
- 'null'
description: A connected-tool call (`assistant.toolbox_tool`, `assistant.toolbox.execute`) or synthetic-tool run (`synthetic_tool.executed`) in words; null on every other row. Names are resolved when you read, so renaming or deleting a connection or client changes how old rows read.
properties:
summary:
type: string
description: Outcome-aware sentence, e.g. "Updated a page in Notion" or "Failed to update a page in Notion".
tool_name:
type: string
description: The catalog tool name, unqualified, when recorded; else the advertised name.
connector:
type:
- object
- 'null'
description: Null when no single connector applies (a synthetic tool) or none was recorded or resolvable.
properties:
slug:
type: string
name:
type: string
logo:
type:
- string
- 'null'
can_view:
type: boolean
description: 'Whether the caller may open this connector (`GET /connector/{slug}`): holds `connector:view` and the catalog resolved the slug.'
toolbox:
type:
- object
- 'null'
description: The stored toolbox the call went through. Null for the built-in all-tools and per-connection sets, for a synthetic-tool row, and for a row that never recorded one.
properties:
id:
type: string
name:
type:
- string
- 'null'
description: Null when the toolbox is gone or the lookup failed.
can_view:
type: boolean
description: 'Whether the caller may open it (`GET /toolbox/{id}`): owner or a grant.'
synthetic_tool:
type:
- object
- 'null'
description: 'The synthetic tool the call ran: a `synthetic_tool.executed` row, or a toolbox call whose tool was a synthetic one. Null for every ordinary connector-tool call.'
properties:
id:
type: string
name:
type: string
description: The name it had when it ran.
can_view:
type: boolean
description: 'Whether the caller may open it (`GET /synthetic-tool/{id}`): its owner only.'
connection:
type:
- object
- 'null'
properties:
id:
type: string
name:
type:
- string
- 'null'
state:
type: string
enum:
- active
- deleted
- unknown
description: '`unknown` means the lookup failed — never read it as deleted.'
can_view:
type: boolean
description: Whether the caller may open this connection (`GET /connection/{id}`).
via:
type: object
properties:
surface:
type:
- string
- 'null'
enum:
- app
- mcp
- api
- console
- null
description: '`app` the Elaichi app''s built-in agent, `console` a person using the Elaichi app itself (a synthetic tool''s Run), `mcp` an MCP client, `api` an org API token. Null when not recorded, never guessed.'
client_id:
type:
- string
- 'null'
client_name:
type:
- string
- 'null'
description: The verified client name when its redirect URIs prove it, else the self-reported name.
client_logo:
type:
- string
- 'null'
client_mark:
type:
- string
- 'null'
enum:
- claude
- chatgpt
- cursor
- grok
- perplexity
- mistral
- devin
- null
description: The verified client's bundled-mark slug; set only when `client_verified` is true.
client_verified:
type: boolean
description: True only when the name and logo come from the verified client.
outcome:
type: string
enum:
- succeeded
- failed
error:
type:
- string
- 'null'
description: Error code (never a message), e.g. `call_failed:429`.
error_message:
type:
- string
- 'null'
description: Fixed plain-English sentence for `error`; null on success.
access:
type:
- string
- 'null'
enum:
- read
- write
- destructive
- null
approval:
type:
- string
- 'null'
enum:
- not_required
- approved_by_person
- always_allowed
- allowed_by_connected_app
- direct_run
- null
description: '`direct_run`: a person ran a synthetic tool directly (in the Elaichi app or with `POST /synthetic-tool/{id}/execute`), so no approval gate asked; this is not the same as `not_required` (a read). On `assistant.toolbox.execute` the requirement follows the tool''s own tier. Null when the row predates the recorded facts, or the source is not one of these.'
arguments_edited:
type:
- boolean
- 'null'
target:
type:
- object
- 'null'
description: What the call touched. A list, search or query has the type alone (id, name and url null). Null when nothing could be identified.
properties:
type:
type:
- string
- 'null'
description: The catalog resource, singular.
id:
type:
- string
- 'null'
description: The path id or the created record's id. Never an email address.
name:
type:
- string
- 'null'
description: The object's title. Always null for a person's record (by resource noun or by response shape), for a message-like record (email, thread, comment, event, post, ...), and when it contains an email address.
url:
type:
- string
- 'null'
description: http(s), no user:password, origin + path only (query and fragment dropped). Null for a create-like call and for any call whose resource or method names a session, signed/temporary/download link, export, portal, checkout, invite or recipient view.
result_count:
type:
- integer
- 'null'
description: Items a list, search or query returned.
next_cursor:
type:
- string
- 'null'
prev_cursor:
type:
- string
- 'null'
'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: 'Lists what happened in this organization, newest first: an append-only trail. Open to every member: with `audit:view` it lists every event in the organization; without it, only the caller''s own events plus events on connections they own or can edit. The response says which, as a top-level `scope` (`org` or `own`) beside the list envelope. An `own` response also carries `connection_scope`: `all`, `one` (a `connection_id` was given), or `too_many` (the caller owns or can edit more connections than one query lists, so the page holds only their own events). Anyone who can edit a connection (the owner, or an `edit` grant direct, through a team, or org-wide) sees every member''s tool calls made through it. Filters combine with AND; `q` additionally matches the actor by name or email. The cursor is opaque: do not parse or construct one. Events are eventually consistent, so one may take a moment to appear after the action that produced it.'
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/OrganizationIdHeader'
- $ref: '#/components/parameters/LimitQuery'
- $ref: '#/components/parameters/CursorQuery'
- name: q
in: query
required: false
description: Matches the action, the resource, or the actor by name/email. `system` matches system-generated rows. LIKE wildcards are matched literally. Max 200 characters.
schema:
type: string
maxLength: 200
- name: category
in: query
required: false
description: Bucket derived from the action name. Any other value is a 400.
schema:
type: string
enum:
- auth
- assistant
- mcp
- toolbox
- file
- connection
- access
- org
- other
- name: action
in: query
required: false
description: Verb class of the action, not the full action name.
schema:
type: string
enum:
- created
- updated
- deleted
- read
- other
- name: actor
in: query
required: false
description: A user id (`usr_…`), or the literal `system` for rows with no human actor. Max 128 characters.
schema:
type: string
maxLength: 128
- name: connection_id
in: query
required: false
description: Only events on this connection (`conn_…`). Needs `audit:view`, or owning the connection, or `edit` on it; otherwise 404, the same as an id that does not exist. Max 128 characters.
schema:
type: string
maxLength: 128
- name: since
in: query
required: false
description: Inclusive lower bound on `created_at`. ISO-8601; anything unparseable is a 400.
schema:
type: string
format: date-time
components:
parameters:
LimitQuery:
name: limit
in: query
required: false
description: Page size. Defaults to 50. Values above 200 are silently clamped to 200 rather than rejected; a value below 1, or a non-integer, is a 400. Ignored by the endpoints documented as unpaginated.
schema:
type: integer
minimum: 1
maximum: 200
default: 50
OrganizationIdHeader:
name: X-Organization-Id
in: header
required: false
description: Target organization (`org_…`). Required for cookie/session auth on org-scoped routes; optional for API tokens, which carry their organization, and rejected when it names a different one.
schema:
type: string
CursorQuery:
name: cursor
in: query
required: false
description: Opaque cursor — pass the `next_cursor` from a previous response. Ignored by unpaginated endpoints.
schema:
type: string
schemas:
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
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.