Deployment-wide, for whoever runs the infrastructure. As a customer you should never need these.
12 operations · 11 captured against the live API.
Rooms, members, tokens #
POST /internal/v1/rooms # Create a room
Registers tenant_id (1–128 characters) as a tenant if it is new. With external_ref the call is idempotent per tenant: repeating it returns the existing room unchanged and ignores the other fields. Without external_ref, every call creates a new room. The room has no members. e2ee and e2ee_scheme (mls or megolm, which requires e2ee: true) are set at creation and cannot change. expires_at is informational only: nothing closes or deletes the room when it passes.
createRoom captured live
Request
curl -X POST https://api.ollacore.com/internal/v1/rooms \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"tenant_id":"acct_fac91b282191cc02dd29912c8db43f1c","created_by":"alice","external_ref":"ops-room-1"}'
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"created_by": "alice",
"external_ref": "ops-room-1"
}
| Parameter | Type | Description |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
tenant_id required | string | The tenant to create the room in, 1–128 characters. |
created_by required | string | The principal recorded as the room's creator. |
external_ref | string | Your own reference for the room. If one with this external_ref exists in the tenant, it is returned instead. |
expires_at | string (date-time) | Optional informational expiry. Nothing closes or deletes the room when it passes. |
Response · 200
{
"id": "00919f0a-cfeb-438d-bdb7-65af28b4f678",
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"external_ref": "ops-room-1",
"created_by": "alice",
"status": "active",
"e2ee": false,
"created_at": "2026-01-15T09:30:02Z"
}
Response fields (9)
| Field | Type | Description |
id required | string (uuid) | The room's id, assigned by the server. |
tenant_id required | string | The tenant that owns the room. |
external_ref | string | Your own reference for the room, if you gave one. Creating a room with an external_ref that already exists in the tenant returns that room. |
created_by required | string | The principal recorded as the room's creator. |
status required | one of: active, closed | active, or closed (no new tokens are minted for it). |
e2ee required | boolean | End-to-end encrypted room. When true, the server accepts only ciphertext message kinds, rejects search and reactions, and pushes are content-free — the client must encrypt before sending. |
e2ee_scheme | one of: mls, megolm | Which client E2EE scheme the room's members run, when the creator declared it: mls (the primary scheme) or megolm (the matrix-sdk-crypto transport). The two cannot share a room. Absent when undeclared and on plaintext rooms. |
created_at required | string (date-time) | When the room was created. |
expires_at | string (date-time) | Informational expiry time, if one was set. Nothing closes or deletes the room when it passes. |
Errors · 400 · 401 · 429
| Status | When |
400 | tenant_id outside 1–128 characters, an invalid e2ee_scheme, or a malformed body. |
401 | Missing, expired or invalid credentials |
429 | Rate limit exceeded |
Resolve by external_ref
Both tenant_id and external_ref are required, and external_ref must match exactly within that tenant. The room is returned whatever its status.
lookupRoom captured live
Request
curl -X GET https://api.ollacore.com/internal/v1/rooms?tenant_id=acct_fac91b282191cc02dd29912c8db43f1c&external_ref=ops-room-1 \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
tenant_id query required | string | The tenant to look in. |
external_ref query required | string | unique per tenant; the same ref always resolves to the same room, which is what makes room creation idempotent |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"id": "00919f0a-cfeb-438d-bdb7-65af28b4f678",
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"external_ref": "ops-room-1",
"created_by": "alice",
"status": "active",
"e2ee": false,
"created_at": "2026-01-15T09:30:02Z"
}
Response fields (9)
| Field | Type | Description |
id required | string (uuid) | The room's id, assigned by the server. |
tenant_id required | string | The tenant that owns the room. |
external_ref | string | Your own reference for the room, if you gave one. Creating a room with an external_ref that already exists in the tenant returns that room. |
created_by required | string | The principal recorded as the room's creator. |
status required | one of: active, closed | active, or closed (no new tokens are minted for it). |
e2ee required | boolean | End-to-end encrypted room. When true, the server accepts only ciphertext message kinds, rejects search and reactions, and pushes are content-free — the client must encrypt before sending. |
e2ee_scheme | one of: mls, megolm | Which client E2EE scheme the room's members run, when the creator declared it: mls (the primary scheme) or megolm (the matrix-sdk-crypto transport). The two cannot share a room. Absent when undeclared and on plaintext rooms. |
created_at required | string (date-time) | When the room was created. |
expires_at | string (date-time) | Informational expiry time, if one was set. Nothing closes or deletes the room when it passes. |
Errors · 401 · 404 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
404 | no room with that external_ref in the tenant |
429 | Rate limit exceeded |
PATCH /internal/v1/rooms/{room_id} # Patch status / expiry
Leave a field out to keep its current value. expires_at cannot be cleared, because null also keeps the current value. status must be active or closed (400 otherwise). Closing a room only stops new session tokens from being minted for it (409 room is closed). Members keep their tokens, open sockets and history, and can still send until their tokens expire. Setting active lifts this. No event is published. expires_at remains informational only.
patchRoom captured live
Request
curl -X PATCH https://api.ollacore.com/internal/v1/rooms/00919f0a-cfeb-438d-bdb7-65af28b4f678 \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"expires_at":"2026-01-16T09:30:02Z"}'
{
"expires_at": "2026-01-16T09:30:02Z"
}
| Parameter | Type | Description |
room_id path required | string (uuid) | The room's id. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
status | one of: active, closed | closed stops new session tokens being minted for the room (409); members keep access with the tokens they hold. active reopens it. |
expires_at | string (date-time) | Informational expiry time, stored and returned. Nothing closes or deletes the room when it passes. |
Response · 200
{
"id": "00919f0a-cfeb-438d-bdb7-65af28b4f678",
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"external_ref": "ops-room-1",
"created_by": "alice",
"status": "active",
"e2ee": false,
"created_at": "2026-01-15T09:30:02Z",
"expires_at": "2026-01-16T09:30:02Z"
}
Response fields (9)
| Field | Type | Description |
id required | string (uuid) | The room's id, assigned by the server. |
tenant_id required | string | The tenant that owns the room. |
external_ref | string | Your own reference for the room, if you gave one. Creating a room with an external_ref that already exists in the tenant returns that room. |
created_by required | string | The principal recorded as the room's creator. |
status required | one of: active, closed | active, or closed (no new tokens are minted for it). |
e2ee required | boolean | End-to-end encrypted room. When true, the server accepts only ciphertext message kinds, rejects search and reactions, and pushes are content-free — the client must encrypt before sending. |
e2ee_scheme | one of: mls, megolm | Which client E2EE scheme the room's members run, when the creator declared it: mls (the primary scheme) or megolm (the matrix-sdk-crypto transport). The two cannot share a room. Absent when undeclared and on plaintext rooms. |
created_at required | string (date-time) | When the room was created. |
expires_at | string (date-time) | Informational expiry time, if one was set. Nothing closes or deletes the room when it passes. |
Errors · 400 · 401 · 404 · 429
| Status | When |
400 | status other than active or closed. |
401 | Missing, expired or invalid credentials |
404 | No such room, or the room is being erased: it cannot be reactivated. |
429 | Rate limit exceeded |
GET /internal/v1/rooms/{room_id}/status # Members, presence, live call roster
member_count counts active members. online_participants lists the members who currently have chat presence. rtc_participants lists the principals in the room's call on the SFU at request time, and is empty when nobody is in the call. If presence cannot be read, online_participants comes back empty and the request still succeeds.
roomStatus captured live
Request
curl -X GET https://api.ollacore.com/internal/v1/rooms/25964f12-9ae9-4356-80e8-69bc5f749bd1/status \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
room_id path required | string (uuid) | The room's id. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"room": {
"id": "25964f12-9ae9-4356-80e8-69bc5f749bd1",
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"external_ref": "order-7781",
"created_by": "alice",
"status": "active",
"e2ee": false,
"created_at": "2026-01-15T09:30:03Z"
},
"member_count": 4,
"online_participants": [],
"rtc_participants": []
}
Response fields (13)
| Field | Type | Description |
room required | Room | The room. |
room.id required | string (uuid) | The room's id, assigned by the server. |
room.tenant_id required | string | The tenant that owns the room. |
room.external_ref | string | Your own reference for the room, if you gave one. Creating a room with an external_ref that already exists in the tenant returns that room. |
room.created_by required | string | The principal recorded as the room's creator. |
room.status required | one of: active, closed | active, or closed (no new tokens are minted for it). |
room.e2ee required | boolean | End-to-end encrypted room. When true, the server accepts only ciphertext message kinds, rejects search and reactions, and pushes are content-free — the client must encrypt before sending. |
room.e2ee_scheme | one of: mls, megolm | Which client E2EE scheme the room's members run, when the creator declared it: mls (the primary scheme) or megolm (the matrix-sdk-crypto transport). The two cannot share a room. Absent when undeclared and on plaintext rooms. |
room.created_at required | string (date-time) | When the room was created. |
room.expires_at | string (date-time) | Informational expiry time, if one was set. Nothing closes or deletes the room when it passes. |
member_count required | integer (int64) | How many active members the room has. |
online_participants required | array of string | principals with a live chat WebSocket |
rtc_participants required | array of string | principals currently published to the SFU |
Errors · 401 · 404 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
404 | No such room, message, member or attachment |
429 | Rate limit exceeded |
POST /internal/v1/rooms/{room_id}/members # Add a member
A room holds at most 5,000 active members, on every plane; once it is full the add is refused with 409 and nothing changes. Restoring a removed member or changing an existing member's role never needs a seat.
addMember captured live
Request
curl -X POST https://api.ollacore.com/internal/v1/rooms/00919f0a-cfeb-438d-bdb7-65af28b4f678/members \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"principal_id":"alice","role":"owner"}'
{
"principal_id": "alice",
"role": "owner"
}
| Parameter | Type | Description |
room_id path required | string (uuid) | The room's id. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
principal_id required | string | Who to add, 1–128 characters. A removed member is restored. |
role | one of: owner, member, viewer default "member" | owner, member or viewer. Defaults to member; anything else is 400. |
Response · 200
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"room_id": "00919f0a-cfeb-438d-bdb7-65af28b4f678",
"principal_id": "alice",
"role": "owner",
"joined_at": "2026-01-15T09:30:02Z"
}
Response fields (7)
| Field | Type | Description |
tenant_id required | string | The tenant that owns the room. |
room_id required | string (uuid) | The room. |
principal_id required | string | The member's principal id. |
role required | string | owner, member or viewer. |
joined_at | string (date-time) | When the principal first joined the room. Restoring a removed member keeps the original time. |
left_at | string (date-time) | set when the member was removed; the row is retained so history stays auditable |
muted_until | string (date-time) | Until when this member has push notifications from the room silenced; absent when not muted. 9999-12-31T00:00:00Z stands for "until unmuted". Live delivery and call rings are unaffected. |
Errors · 401 · 404 · 409 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
404 | No such room, message, member or attachment |
409 | Conflicts with current state |
429 | Rate limit exceeded |
DELETE /internal/v1/rooms/{room_id}/members/{principal_id} # Remove a member
Sets the membership's left_at; history is kept, and adding the principal again restores the membership. The removal takes effect at once: the member's live chat and RTC sockets close with 4403, and their HTTP requests and new session tokens are refused. A durable member.removed event goes to the room's connected clients and to webhooks subscribed to it. E2EE clients use this event as the cue to rotate keys. 404 if the room does not exist or the principal is not an active member.
removeMember captured live
Request
curl -X DELETE https://api.ollacore.com/internal/v1/rooms/00919f0a-cfeb-438d-bdb7-65af28b4f678/members/carol2 \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
room_id path required | string (uuid) | The room's id. |
principal_id path required | string | The member to remove. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"removed": true
}
Response fields (1)
| Field | Type | Description |
removed required | boolean | Always true: removing a principal who is not an active member answers 404. |
Errors · 401 · 404 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
404 | No such room, message, member or attachment |
429 | Rate limit exceeded |
POST /internal/v1/session-tokens # Mint a token
role defaults to the member's stored role and may only lower it: a token above the member's role (viewer → owner) is refused with 403, a role outside owner|member|viewer with 400.
mintSessionToken captured live
Request
curl -X POST https://api.ollacore.com/internal/v1/session-tokens \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"tenant_id":"acct_fac91b282191cc02dd29912c8db43f1c","room_id":"00919f0a-cfeb-438d-bdb7-65af28b4f678","principal_id":"alice","role":"owner","ttl_seconds":3600}'
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"room_id": "00919f0a-cfeb-438d-bdb7-65af28b4f678",
"principal_id": "alice",
"role": "owner",
"ttl_seconds": 3600
}
| Parameter | Type | Description |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
tenant_id required | string | The tenant the room belongs to. |
room_id required | string (uuid) | The room the token is for. A token opens exactly one room. |
principal_id required | string | Who the token is for. Must be an active member of the room. |
role | one of: owner, member, viewer | Optional: mint with fewer rights than the member has. At or below the member's stored role (a higher one is 403); anything but owner|member|viewer is 400. Omit to use the member's own role. |
ttl_seconds | integer default 600 · min 60 · max 3600 | Token lifetime in seconds. Defaults to 600 and is clamped to 60–3600. |
Response · 200
{
"access_token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImEwM2I1NjQ4MjM3YjlmZWIifQ.eyJpc3MiOiJjaGF0Ym94LWJhY2tlbmQiLCJhdWQiOiJjaGF0Ym94LXJlYWx0aW1lIiwic3ViIjoiYWxpY2UiLCJ0aWQiOiJhY2N0X2ZhYzkxYjI4MjE5MWNjMDJkZDI5OTEyYzhkYjQzZjFjIiwicmlkIjoiMDA5MTlmMGEtY2ZlYi00MzhkLWJkYjctNjVhZjI4YjRmNjc4Iiwicm9sZSI6Im93bmVyIiwicGVybWlzc2lvbnMiOlsiY2hhdDpzZW5kIiwiY2hhdDpoaXN0b3J5IiwiYXR0YWNobWVudDp1cGxvYWQiLCJhdHRhY2htZW50OmRvd25sb2FkIiwicnRjOnB1Ymxpc2giLCJydGM6c3Vic2NyaWJlIl0sImp0aSI6ImJmZThlYzg2LTVkZmUtNDM1YS1iNTk3LTkwZjBkY2RhM2FiZSIsImlhdCI6MTc5MjMyNDY2NSwibmJmIjoxNzkyMzI0NjY1LCJleHAiOjE3OTIzMjgyNjV9.SIGNATURE_REMOVED",
"expires_at": "2026-01-15T10:30:02Z",
"rtc_websocket_url": "wss://api.ollacore.com/v1/rtc/ws",
"chat_websocket_url": "wss://api.ollacore.com/v1/chat/ws",
"ice_servers": [
{
"urls": [
"stun:api.ollacore.com:3478"
]
},
{
"urls": [
"turn:api.ollacore.com:3478",
"turns:api.ollacore.com:5349"
],
"username": "1789064267:alice",
"credential": "EXAMPLE_TURN_CREDENTIAL="
}
]
}
Response fields (8)
| Field | Type | Description |
access_token required | string | The room-scoped session token (an Ed25519-signed JWT). Present it as Authorization: Bearer … over HTTP and as the WebSocket subprotocol bearer.<token>, never in a URL. |
expires_at required | string (date-time) | When the token expires. Mint a new one before then; a socket closes with 4401 at expiry. |
rtc_websocket_url required | string (uri) | The call-signalling WebSocket URL. |
chat_websocket_url required | string (uri) | The chat WebSocket URL. |
ice_servers required | array of object | STUN and TURN servers for WebRTC, with short-lived TURN credentials. Pass them to RTCPeerConnection unchanged. |
ice_servers[].urls required | array of string | The server URLs. They never carry a ?transport= query, which Safari refuses. |
ice_servers[].username | string | expiry_unix:principal — ephemeral, 600 s |
ice_servers[].credential | string | base64(HMAC-SHA1(turn_secret, username)) |
Errors · 400 · 401 · 403 · 404 · 429
| Status | When |
400 | role is not one of owner | member | viewer. |
401 | Missing, expired or invalid credentials |
403 | The principal is not an active member of the room, or role is above the member's stored role (a viewer cannot be minted an owner token). |
404 | Room not found in tenant |
429 | Rate limit exceeded |
GET /internal/v1/principals/{principal_id}/unread # Per-room unread for a principal
tenant_id is required. Lists every room where the principal is an active member, including rooms with no unread messages. A room's count is the messages after the principal's read cursor, excluding their own and deleted messages, and total is the sum. A principal with no memberships gets total: 0 and an empty list.
principalUnread captured live
Request
curl -X GET https://api.ollacore.com/internal/v1/principals/bob/unread?tenant_id=acct_fac91b282191cc02dd29912c8db43f1c \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
principal_id path required | string | The principal whose unread counts to return. |
tenant_id query required | string | The tenant the principal belongs to. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"rooms": [
{
"room_id": "25964f12-9ae9-4356-80e8-69bc5f749bd1",
"unread_count": 0
}
],
"total": 0
}
Response fields (4)
| Field | Type | Description |
total required | integer (int64) | Unread messages across all the principal's rooms, for an app-icon badge. |
rooms required | array of object | Per-room unread counts. |
rooms[].room_id required | string (uuid) | The room. |
rooms[].unread_count required | integer (int64) | Messages after the principal's read cursor in that room. |
Errors · 401 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
429 | Rate limit exceeded |
Provisioning & lifecycle #
POST /internal/v1/api-keys # Issue a customer key
environment is live or test. A test key works in a separate {tenant_id}::test sandbox with its own rooms, messages and usage, so tenant_id may not contain ::. Each scope must be one of rooms:read, rooms:write, members:write, tokens:mint, messages:write, webhooks:manage, usage:read, rooms:delete or data:erase. plan defaults to default and must already exist. Any invalid value is 400. The tenant, and for a test key its sandbox, is registered if new. api_key (ak_<env>_<id>.<secret>) is returned only once, because the server stores only a SHA-256 digest of the secret. After expires_at the key is refused with 401.
createApiKey captured live
Request
curl -X POST https://api.ollacore.com/internal/v1/api-keys \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"tenant_id":"acct_fac91b282191cc02dd29912c8db43f1c","name":"sandbox-key","environment":"test","scopes":["rooms:read","rooms:write"]}'
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"name": "sandbox-key",
"environment": "test",
"scopes": [
"rooms:read",
"rooms:write"
]
}
| Parameter | Type | Description |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
tenant_id required | string | The tenant the key acts on, 1–128 characters. Must not contain ::, which is reserved for the test namespace. |
name | string | Optional label for the key. |
environment required | one of: live, test | live or test. A test key works in the {tenant_id}::test namespace. |
scopes required | array of one of: rooms:read, rooms:write, members:write, tokens:mint, messages:write, webhooks:manage, usage:read, rooms:delete, data:erase | The scopes to grant. Each must be a known scope. |
expires_at | string (date-time) | Optional expiry. After it the key is refused as if revoked. |
plan | string | Rate-tier plan name (see the plans table); defaults to 'default'. |
Response · 200
{
"key_id": "key-id-sandbox",
"api_key": "ak_live_EXAMPLE.NOT_A_REAL_KEY",
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"environment": "test",
"scopes": [
"rooms:read",
"rooms:write"
]
}
Response fields (5)
| Field | Type | Description |
key_id required | string | The key's public id (ak_live_… or ak_test_…). Use it to revoke the key; it is not a credential. |
api_key required | string | Full ak_<env>_<id>.<secret>, shown once. |
tenant_id required | string | The tenant the key acts on. A test key's data lives in its own namespace, {tenant_id}::test, and never mixes with live data. |
environment required | one of: live, test | live or test. A test key sees only test data. |
scopes required | array of one of: rooms:read, rooms:write, members:write, tokens:mint, messages:write, webhooks:manage, usage:read, rooms:delete, data:erase | What the key may do. A call outside these scopes is refused with 403 when it is made, not when the key is created. |
Errors · 400 · 401 · 429
| Status | When |
400 | A bad environment, scope, plan or tenant_id. |
401 | Missing, expired or invalid credentials |
429 | Rate limit exceeded |
DELETE /internal/v1/api-keys/{key_id} # Revoke a key
Takes effect on the key's next request, which is refused with 401. 404 if the id is unknown or the key is already revoked. Session tokens the key already minted stay valid until they expire, at most one hour. After revocation the key's plan no longer counts toward the tenant's quotas or retention window.
revokeApiKey captured live
Request
curl -X DELETE https://api.ollacore.com/internal/v1/api-keys/key-id-sandbox \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
key_id path required | string | The API key's public id (ak_live_… or ak_test_…). |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"revoked": true
}
Response fields (1)
| Field | Type | Description |
revoked | boolean | True once the key no longer works. |
Errors · 401 · 404 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
404 | No such room, message, member or attachment |
429 | Rate limit exceeded |
PUT /internal/v1/plans/{name} # Create/update a rate + quota plan
Replaces the whole plan. Optional fields left out become null: unlimited quota, no plan retention, no description. name is 1–64 characters, rate_limit and rate_window_seconds must be positive, and quotas and retention_days must be at least 0 or null; anything else is 400. Plans are global. The rate limit applies per key, from that key's next request. For each quota and for retention, a tenant gets the most generous plan among its live keys, and null counts as unlimited. A tenant's own retention setting overrides the plan's. Monthly quotas count message.sent and attachment.bytes per UTC calendar month.
putPlan captured on a test deployment
Request
curl -X PUT https://api.ollacore.com/internal/v1/plans/docs-example \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG" \
-H "Content-Type: application/json" \
-d '{"rate_limit":120,"rate_window_seconds":10,"monthly_message_quota":5000000,"monthly_byte_quota":549755813888,"retention_days":365,"description":"Example tier for documentation"}'
{
"rate_limit": 120,
"rate_window_seconds": 10,
"monthly_message_quota": 5000000,
"monthly_byte_quota": 549755813888,
"retention_days": 365,
"description": "Example tier for documentation"
}
| Parameter | Type | Description |
name path required | string | The plan's name, 1–64 characters. The call creates the plan or replaces it. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
rate_limit required | integer (int64) | Requests allowed per window, per API key on this plan. Must be positive. |
rate_window_seconds required | integer (int64) | The rate-limit window in seconds. Must be positive. |
monthly_message_quota | integer (int64), nullable | Monthly message cap; omit or null for unlimited. |
monthly_byte_quota | integer (int64), nullable | Monthly attachment-byte cap; omit or null for unlimited. |
retention_days | integer (int64), nullable | Auto-expire messages older than this many days; omit or null to keep forever. |
description | string | Optional human description of the plan. |
Response · 200
{
"plan": "docs-example"
}
Response fields (1)
| Field | Type | Description |
plan | string | The plan's name. |
Errors · 400 · 401 · 429
| Status | When |
400 | A name outside 1–64 characters, a rate limit or window that is not positive, or a negative quota or retention. |
401 | Missing, expired or invalid credentials |
429 | Rate limit exceeded |
Captured against a test deployment: `plans` is deployment-wide, so writing it on production would re-tier every existing tenant.
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
Async, in two steps. At once, every way in is revoked: the tenant's account (and its sessions), API keys, directory apps, pending OTP challenges and directory sessions. About 45 seconds later — long enough for any request already in flight to finish — every room is purged (blobs, rows and every stored copy of its events), then the rest of the tenant's data: usage ledger, webhooks and their delivery log, push subscriptions, identities, the directory, and E2EE key material. Most destructive; HMAC-only.
purgeTenant captured live
Request
curl -X DELETE https://api.ollacore.com/internal/v1/tenants/acct_fac91b282191cc02dd29912c8db43f1c \
-H "X-Chatbox-Key-Id: $KEY_ID" \
-H "X-Chatbox-Timestamp: $TS" \
-H "X-Chatbox-Nonce: $NONCE" \
-H "X-Chatbox-Signature: $SIG"
| Parameter | Type | Description |
tenant_id path required | string | The tenant to erase. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"purging": true
}
Response fields (1)
| Field | Type | Description |
purging required | boolean | True: every room and all of the tenant's data are being erased in the background. Irreversible. |
Errors · 401 · 429
| Status | When |
401 | Missing, expired or invalid credentials |
429 | Rate limit exceeded |