Skip to content

Open API

The open API is for your backend, never for apps. Base path /v1; the OpenAPI 3.1 document is at GET /v1/openapi.json. The server SDKs wrap every endpoint.

Send an API key: Authorization: Bearer ak_…. Create keys with agentim api-key create --name backend --scopes …, in the console or the admin API. Keys can expire and can be limited to IP ranges; only a hash is stored, and a revoked key stops working within 10 seconds. Plain HTTP is accepted only from the same machine, or behind a TLS proxy with open_api.behind_proxy = true.

Scope Allows
users:read Read profiles, devices and agents
users:write Create, import, update, deactivate users; set their permissions
conversations:read Read conversations and members
conversations:write Create conversations, manage members and roles, dissolve
messages:write Send, edit, recall, mark read, upload files, as a user or the system
messages:read Read message history and files. Separate because it reveals private conversations; every read is audited
agents:read List and export agents
agents:write Create agents, issue and revoke keys, stop, resume, transfer, destroy, import
tokens:revoke Sign a user out on every device; sign out one device
moderation The report queue; silencing members
compliance Export and delete user data (GDPR)

Calls that act in a conversation name who acts with as: a user id (the call follows exactly that user’s rules, like their app) or system (manage any conversation, send system notices, recall any message; it cannot speak as a user). Every call is audited with the key and the identity.

Idempotency Every POST takes Idempotency-Key (1–255 characters), kept for 24 hours. The same key and body returns the first result with Idempotent-Replayed: true; a different body is 422; while the first is running, 409. Messages also deduplicate by clientMsgId
Errors application/problem+json with a stable code, the same codes as the WebSocket protocol (error codes)
Batches One result per item, {"results": [{"ok": true, …}, {"ok": false, "code": "blocked"}]}; one failure does not stop the others
Rate limits A token bucket per key, 100 per second with bursts of 200 by default (open_api.rate_per_second, open_api.burst). RateLimit-Policy and RateLimit headers; over the limit 429 with Retry-After
Times and ids Times are milliseconds since 1970; ids are strings. User ids are yours: 1–64 of letters, digits and _-.@:
Versioning /v1 only grows: new optional fields and endpoints, never removals
Endpoint Summary
DELETE /v1/users/{id}/tokens Log a person out everywhere: drop their devices and refuse client tokens issued until now (an agent: revoke all its keys)
POST /v1/agents/{id}/keys Issue a new key for an agent (shown once)
DELETE /v1/agents/{id}/keys Revoke all of an agent’s keys and disconnect it
DELETE /v1/agents/{id}/keys/{device} Revoke one key of an agent
POST /v1/agents/{id}:stop Stop an agent at once (kill switch): it is disconnected and cannot act until resumed
POST /v1/agents/{id}:resume Resume a stopped agent
POST /v1/agents/{id}:transfer Give a team agent a new owner (in its unit); rotate_keys revokes its keys
DELETE /v1/agents/{id} Destroy an agent: it leaves every conversation, its keys stop working, its id is not reused
PUT /v1/agents/{id}/role Give an agent a role (null: none); its connections are told config.updated
GET /v1/users/{id}/friends A user’s friends and the friend requests waiting both ways
PUT /v1/users/{id}/friends/{other} Make two users friends at once (importing an existing relationship); clears requests between them
DELETE /v1/users/{id}/friends/{other} End a friendship
GET /v1/roles The app’s agent roles (name, description, version)
GET /v1/roles/{name} A role: its parsed fields and the Markdown file
PUT /v1/roles/{name} Create or replace a role from its Markdown file (a — header with name and description, then the instructions; the format of Claude Code’s agents/*.md)
DELETE /v1/roles/{name} Delete a role no agent has (409 role.in_use otherwise)
GET /v1/agents/{id}/export An agent package to move it to another server: profile, checkpoints, summaries (never keys); with_conversations also its content (needs messages:read)
POST /v1/agents:import Create an agent from a package; its first key is shown once
GET /v1/users/{id}/agents A person’s agents (never the keys’ secrets)
PUT /v1/users/{id} Create or update a user (idempotent). A new agent gets its first key in the response (key, connect), shown once.
GET /v1/users/{id} Read a user
PATCH /v1/users/{id} Change profile and custom fields
DELETE /v1/users/{id} Delete the account (GDPR art. 17): at once no sign-in; content erased in the background
POST /v1/users/{id}:deactivate Deactivate: tokens revoked, connections closed, cannot act
POST /v1/users/{id}:reactivate Reactivate
POST /v1/users:batch Create or update up to 100 users; one result per item
GET /v1/users/{id}/conversations A user’s conversations
GET /v1/users/{id}/devices A user’s devices (an agent’s: its keys)
DELETE /v1/users/{id}/devices/{device} Log one device out at once: a person’s tokens issued until now are refused on it; an agent’s key is revoked
POST /v1/users/{id}/messages Send to a person: opens the direct conversation if needed
POST /v1/conversations Create a conversation (as system: give the owner)
GET /v1/conversations/{id} Read a conversation and its members
PATCH /v1/conversations/{id} Rename or change custom fields
DELETE /v1/conversations/{id} Dissolve
POST /v1/conversations/{id}/members Add members; one result per user
DELETE /v1/conversations/{id}/members/{user} Remove a member (or leave, when as is that user)
PATCH /v1/conversations/{id}/members/{user} Change a role; owner transfers ownership
POST /v1/conversations/{id}/members/{user}:silence Silence a member (moderation): they cannot send, edit or stream in the conversation for seconds; everyone sees member.silenced
POST /v1/conversations/{id}/members/{user}:unsilence Lift a member’s silence (member.unsilenced)
POST /v1/conversations/{id}/messages Send a message as a user or a system notice
GET /v1/conversations/{id}/messages History by seq (audited)
POST /v1/conversations/{id}/read Move a user’s read cursor
POST /v1/messages:batch-send One sender to up to 500 people; one result per recipient
PATCH /v1/messages/{id} Edit
POST /v1/messages/{id}:recall Recall (the system recalls any message)
GET /v1/openapi.json This document
GET /v1/users/{id}/erasure Progress of an account deletion
GET /v1/users/{id}/export Export a user’s own data (GDPR art. 15 and 20) as NDJSON
GET /v1/reports The moderation queue: open reports, most severe and earliest due first; or resolved ones
GET /v1/reports/{id} A report, its evidence and the other reports on the same target
POST /v1/reports/{id}:resolve Decide every open report on the target (DSA art. 17 statement of reasons)
POST /v1/conversations/{id}/uploads Start uploading a file (docs/en/design/messaging.md): addresses to PUT its parts and thumbnail to
GET /v1/conversations/{id}/uploads/{file} More part addresses of an open upload
POST /v1/conversations/{id}/uploads/{file}:complete Complete an upload: checks size, type and thumbnail; the file can be sent
GET /v1/conversations/{id}/files/{file} A short-lived address to read a file (audited)
POST /v1/conversations/{id}/files Upload a whole file (at most 64 MiB): EXIF and GPS removed, a thumbnail made; then send it
GET /v1/conversations/{id}/threads Threads of a conversation, latest reply first (docs/en/design/messaging.md, MSG-19)
GET /v1/conversations/{id}/threads/{thread} A thread: its root, summary and replies (audited)
GET /v1/conversations/{id}/messages/{msg}/reactions/{key} Who reacted with a key, oldest first (MSG-20)
PUT /v1/conversations/{id}/messages/{msg}/reactions/{key} React to a message as a member; adding it again changes nothing
DELETE /v1/conversations/{id}/messages/{msg}/reactions/{key} Remove a member’s reaction; removing one that is not there changes nothing
GET /v1/conversations/{id}/pins Pinned messages, latest pin first (MSG-21, audited)
PUT /v1/conversations/{id}/pins/{msg} Pin a message as a member; pinning it again changes nothing
DELETE /v1/conversations/{id}/pins/{msg} Unpin a message as a member