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.
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 →
| POST | /v1/directory/otp/request |
| POST | /v1/directory/otp/verify |
| POST | /v1/directory/logout |
| GET | /v1/directory/me |
| PATCH | /v1/directory/me |
| DELETE | /v1/directory/me |
| POST | /v1/directory/me/avatar/init |
| POST | /v1/directory/me/avatar/complete |
| DELETE | /v1/directory/me/avatar |
| GET | /v1/directory/users/{user_id}/avatar |
| POST | /v1/directory/contacts/lookup |
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 →
| POST | /v1/account/signup |
| POST | /v1/account/login |
| POST | /v1/account/logout |
| GET | /v1/account/api-keys |
| POST | /v1/account/api-keys |
| POST | /v1/account/api-keys/{key_id}/rotate |
| DELETE | /v1/account/api-keys/{key_id} |
| POST | /v1/account/directory-apps |
| GET | /v1/account/directory-apps |
| DELETE | /v1/account/directory-apps/{app_id} |
| GET | /v1/server/usage |
Data erasure #
Erase a person, a room or a user's own account — rows and stored files alike. Guide →
| POST | /v1/server/principals/{principal_id}/erase |
| DELETE | /v1/server/rooms/{room_id} |
| DELETE | /v1/directory/me |
By credential #
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
| POST | /v1/rooms/{room_id}/attachments/init | Begin an upload |
| POST | /v1/rooms/{room_id}/attachments/{attachment_id}/complete | Finish and verify |
| POST | /v1/rooms/{room_id}/attachments/init-multipart | Begin a multipart upload |
| POST | /v1/rooms/{room_id}/attachments/{attachment_id}/complete-multipart | Finish multipart |
| GET | /v1/rooms/{room_id}/attachments/{attachment_id}/download | Presigned download |
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
codeandmessage— see Errors & rate limits. /v1is additive-only, with a 90-day deprecation notice signalled byDeprecationandSunsetheaders.- Writes that can be retried take an idempotency key (
client_message_idfor messages,external_reffor rooms). - Unknown fields are rejected rather than ignored — sending
tenant_idin a body on the server plane is a422, 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.
/openapi.json and
generate a typed client. See
WebSocket protocol for the socket frames.
/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 →