Reference

API reference

The complete shipped surface — 117 HTTP operations across five planes, plus two WebSocket channels documented separately. Find them by feature — messaging, groups, calls, media, identity and the rest — or by the credential each plane takes, which is the thing most likely to trip you up. Every path links to a worked example.

The examples are recordings, not illustrations. All 117 were captured by driving a throwaway tenant through the real API, then redacting the result — so a shape you copy from here is a shape the server actually returned. 112 came from the production deployment; the remaining 5 are marked where they differ.

By feature #

What you are building, and every operation it takes — whichever credential calls it. Each links to its full entry: what it does, its fields, a recorded request and response, and its errors.

Messaging #

Send, edit, delete, react, search, read receipts and unread counts — over HTTP or the chat socket. Guide →

Groups #

Create groups of up to 5,000, with owners as admins, members, invite links and leaving. Guide →

Direct chats and the chat list #

One-to-one conversations, the inbox with last message and unread count, and room tokens. Guide →

Identity, profiles and contacts #

Phone sign-in, profile name, about line and photo, contact discovery, sign-out and account deletion. Guide →

Mute, block and moderation #

Per-chat mute, blocking, and your server deciding what each member may send, see and publish. Guide →

Calls #

Audio, video and screen share over the RTC socket; from your server, layer pins, who receives what, and closing one connection. Guide →

Photos, video, voice notes and files #

Direct-to-storage uploads, verified before use, with thumbnails, posters and large-file multipart. Guide →

Push and devices #

Web Push, FCM and APNs with your credentials, including ringing for incoming calls. Guide →

Agents and bots #

Register a non-human sender and post as it; its messages carry sender_kind everywhere they go. Guide →

Webhooks #

Signed, retried, replayable delivery of every durable event to your server. Guide →

End-to-end encryption #

MLS key packages and group state, and the Megolm/Olm key transport. Guide →

Accounts, keys and usage #

Self-serve signup, API keys with scopes and a test sandbox, directory apps, and metered usage. Guide →

Data erasure #

Erase a person, a room or a user's own account — rows and stored files alike. Guide →

By credential #

ak_ server key

Customer server API

24 operations

room-scoped session token

Client API

31 operations

du_ directory session — or none for OTP

Directory (end-user) API

36 operations

as_ account session

Account API

11 operations

HMAC-signed

Operator control plane

12 operations

none / internal

Operational

3 operations

Customer server API #

Credential: ak_ server key

Your backend calls these. Tenant comes from the key — a tenant_id in a body is rejected. Scope-gated.

Rooms & members

POST /v1/server/rooms Provision a room (idempotent on external_ref)
GET /v1/server/rooms/{room_id} Fetch a room
DELETE /v1/server/rooms/{room_id} Erase a room — rows and blobs
POST /v1/server/rooms/{room_id}/members Add or restore a member (409 once the room holds 5,000)
DELETE /v1/server/rooms/{room_id}/members/{principal_id} Remove a member
PUT /v1/server/rooms/{room_id}/members/{principal_id}/mute Silence the room's push for a member — 8h, 1w or always (members:write)
DELETE /v1/server/rooms/{room_id}/members/{principal_id}/mute Unmute (idempotent)
PUT /v1/server/rooms/{room_id}/members/{principal_id}/preferences Pin which simulcast layer of a publisher's track the member receives — low, medium, high or auto (members:write)
GET /v1/server/rooms/{room_id}/members/{principal_id}/preferences What is pinned for the member, and whether they are in the call (rooms:read)
PUT /v1/server/rooms/{room_id}/members/{principal_id}/rtc-policy Restrict what the member may publish and receive, which peers it sees, how many devices it may bring, and its chat and attachment rights — revisioned, live within about a second (members:write)
GET /v1/server/rooms/{room_id}/members/{principal_id}/rtc-policy The member's stored policy and how far it has reached their live connections, per component (rooms:read)
DELETE /v1/server/rooms/{room_id}/members/{principal_id}/rtc-policy Back to role-only rights — a write in the same revision sequence, ?revision= required (members:write)
GET /v1/server/rooms/{room_id}/rtc/forwarding Who receives whose media in the call right now, with the simulcast layer (rooms:read)
DELETE /v1/server/rooms/{room_id}/rtc/connections/{client_id} Close one of a member's call connections (4413), keeping the membership — their other devices stay in (members:write)

Tokens, principals, messages

POST /v1/server/session-tokens Mint a room-scoped client token
POST /v1/server/principals Register a principal (bot/service identity)
POST /v1/server/principals/{principal_id}/erase GDPR erase a principal
POST /v1/server/rooms/{room_id}/messages Send as a principal (server-side)

Usage & webhooks

GET /v1/server/usage Metered usage for a window
POST /v1/server/webhooks Create an endpoint subscription
GET /v1/server/webhooks List endpoints
DELETE /v1/server/webhooks/{webhook_id} Delete an endpoint
GET /v1/server/webhooks/{webhook_id}/deliveries Delivery audit log
POST /v1/server/webhooks/{webhook_id}/deliveries/{delivery_id}/replay Replay a delivery

Client API #

Credential: room-scoped session token

What your app calls directly. Every path is authorised against the token’s room and principal.

Messages

POST /v1/rooms/{room_id}/messages Send
GET /v1/rooms/{room_id}/messages History (after_seq / before_seq / limit)
PATCH /v1/rooms/{room_id}/messages/{message_id} Edit (author only)
DELETE /v1/rooms/{room_id}/messages/{message_id} Soft delete
GET /v1/rooms/{room_id}/messages/search Full-text search within the room
POST /v1/rooms/{room_id}/messages/{message_id}/reactions Add a reaction
DELETE /v1/rooms/{room_id}/messages/{message_id}/reactions Remove a reaction

Receipts & presence

POST /v1/rooms/{room_id}/messages/{message_id}/delivered Delivery receipt
POST /v1/rooms/{room_id}/messages/{message_id}/read Read receipt (advances cursor)
GET /v1/rooms/{room_id}/unread Unread count and cursors
GET /v1/rooms/{room_id}/participants Room participants

Attachments

Push

POST /v1/push/subscriptions Register a Web Push subscription
DELETE /v1/push/subscriptions Unregister one
GET /v1/push/vapid-public-key VAPID public key

End-to-end encryption

POST /v1/e2ee/keys/upload Publish device + one-time keys
POST /v1/e2ee/keys/query Query devices for principals
POST /v1/e2ee/keys/claim Claim a one-time key (atomic)
POST /v1/e2ee/todevice Send a to-device message
GET /v1/e2ee/todevice Fetch queued to-device messages
POST /v1/keypackages Upload MLS key packages
GET /v1/keypackages/count Remaining key-package count
GET /v1/rooms/{room_id}/keypackages/{principal_id} Consume one key package
PUT /v1/rooms/{room_id}/mls/group-info Publish the MLS GroupInfo + ratchet tree
GET /v1/rooms/{room_id}/mls/group-info Latest GroupInfo + ratchet tree

Experimental

POST /experimental/rtc/session Observe your own accepted RTC session by its handle — not GA, and absent unless the deployment enables it

Deprecated

GET /v1/rooms/{room_id}/recordings Sunset 2027-01-05 — camera feeds were withdrawn; always an empty list, with Deprecation and Sunset headers

Directory (end-user) API #

Credential: du_ directory session — or none for OTP

The turnkey identity plane. Your client calls these directly.

Sign-in & profile

POST /v1/directory/otp/request Request a one-time code (unauthenticated)
POST /v1/directory/otp/verify Verify and receive a du_ session
POST /v1/directory/logout Revoke this session (or every device)
GET /v1/directory/me Current user: id, phone, display_name, about, avatar_version
PATCH /v1/directory/me Update display name and/or about line
DELETE /v1/directory/me Delete my account: leave every chat (groups pass to the next member), erase my data, sign out everywhere
POST /v1/directory/me/avatar/init Start a profile-photo upload (JPEG/PNG/WebP/GIF, ≤ 2 MiB)
POST /v1/directory/me/avatar/complete Make the uploaded bytes your photo — verified before it answers
DELETE /v1/directory/me/avatar Remove your profile photo
GET /v1/directory/users/{user_id}/avatar A user's photo: 302 to the bytes, ETag = avatar_version

Contacts & conversations

POST /v1/directory/contacts/lookup Which phone numbers are registered (≤500)
POST /v1/directory/conversations/direct Open a 1:1 (idempotent; blocked across a block)
POST /v1/directory/conversations/group Create a group
GET /v1/directory/conversations List conversations
GET /v1/directory/conversations/{room_id}/token Mint a room token
GET /v1/directory/inbox Chat list: peer, last message, unread, muted_until

Group management

GET /v1/directory/conversations/{room_id} A conversation as a member sees it: name, description, icon, size
PATCH /v1/directory/conversations/{room_id} Owner: rename a group, set its description or icon
GET /v1/directory/conversations/{room_id}/members Members, owners first
POST /v1/directory/conversations/{room_id}/members Owner: add up to 256 members (409 once the room holds 5,000)
PUT /v1/directory/conversations/{room_id}/members/{user_id} Owner: make a member an owner, or an owner a member
DELETE /v1/directory/conversations/{room_id}/members/{user_id} Owner: remove a member
POST /v1/directory/conversations/{room_id}/leave Leave a group; a lone owner's seat passes to the longest-standing member

Invite links

POST /v1/directory/conversations/{room_id}/invites Owner: create a link — the token is shown once
GET /v1/directory/conversations/{room_id}/invites Owner: live links, without tokens
DELETE /v1/directory/conversations/{room_id}/invites/{invite_id} Owner: revoke a link
POST /v1/directory/invites/preview What a link leads to, before joining (token in the body)
POST /v1/directory/invites/join Join a group through a link

Mute & block

PUT /v1/directory/conversations/{room_id}/mute Silence this conversation's push for yourself — 8h, 1w or always
DELETE /v1/directory/conversations/{room_id}/mute Unmute
GET /v1/directory/blocks Your block list
PUT /v1/directory/blocks/{user_id} Block a user — the direct chat freezes for both
DELETE /v1/directory/blocks/{user_id} Unblock

Devices

POST /v1/directory/devices Register a push token
GET /v1/directory/devices List devices
DELETE /v1/directory/devices Unregister a push token

Account API #

Credential: as_ account session

Self-serve control surface. Dashboard/admin credential — never ship it in a product build.

Account

POST /v1/account/signup Create an account and its tenant
POST /v1/account/login Log in
POST /v1/account/logout Invalidate the session

API keys

GET /v1/account/api-keys List keys
POST /v1/account/api-keys Create a key (secret shown once)
POST /v1/account/api-keys/{key_id}/rotate Rotate atomically
DELETE /v1/account/api-keys/{key_id} Revoke

Directory apps

POST /v1/account/directory-apps Provision an app (webhook or SMS provider)
GET /v1/account/directory-apps List apps and which push transports are configured
DELETE /v1/account/directory-apps/{app_id} Delete an app
PUT /v1/account/directory-apps/{app_id}/push Set FCM/APNs credentials (write-only)

Operator control plane #

Credential: HMAC-signed

Deployment-wide, for whoever runs the infrastructure. As a customer you should never need these.

Rooms, members, tokens

POST /internal/v1/rooms Create a room
GET /internal/v1/rooms Resolve by external_ref
PATCH /internal/v1/rooms/{room_id} Patch status / expiry
GET /internal/v1/rooms/{room_id}/status Members, presence, live call roster
POST /internal/v1/rooms/{room_id}/members Add a member
DELETE /internal/v1/rooms/{room_id}/members/{principal_id} Remove a member
POST /internal/v1/session-tokens Mint a token
GET /internal/v1/principals/{principal_id}/unread Per-room unread for a principal

Provisioning & lifecycle

POST /internal/v1/api-keys Issue a customer key
DELETE /internal/v1/api-keys/{key_id} Revoke a key
PUT /internal/v1/plans/{name} Create/update a rate + quota plan
DELETE /internal/v1/tenants/{tenant_id} Offboard a tenant — revokes the account and its logins, keys and directory at once, then erases rooms, blobs, webhooks and usage

Operational #

Credential: none / internal

Health and telemetry. Metrics are not publicly exposed.

Health

GET /health/live Liveness
GET /health/ready Readiness (dependencies)
GET /metrics Prometheus metrics — internal only

Conventions #

  • All bodies are JSON; all timestamps are RFC 3339 UTC.
  • Errors carry code and message — see Errors & rate limits.
  • /v1 is additive-only, with a 90-day deprecation notice signalled by Deprecation and Sunset headers.
  • Writes that can be retried take an idempotency key (client_message_id for messages, external_ref for rooms).
  • Unknown fields are rejected rather than ignored — sending tenant_id in a body on the server plane is a 422, because the tenant comes from the key.
  • E2EE endpoints require a token minted with an explicit device_id. Without one they refuse, which is easy to misread as a permissions problem. See End-to-end encryption.
The machine-readable OpenAPI document is the source of truth and is kept in lockstep with the router by a parity check that fails the build — an endpoint cannot ship undocumented, and a documented endpoint cannot vanish. Download it at /openapi.json and generate a typed client. See WebSocket protocol for the socket frames.
Try it in Postman. Import /ollacore.postman_collection.json (File → Import → Link). It holds every customer-facing operation with its recorded example, plus a Quickstart folder that runs top to bottom — sign up, create a test key, provision a room, mint a token, send. Details →