CLEMA protocol

Message Format

Every message is a JSON object with a fixed structure:

{
  "id": "string",
  "type": "string",
  "conversation_id": "string",
  "seq": "string",
  "ok": true,
  "data": {},
  "error": {}
}

Fields

Field Type Required Description
id string No Request ID for request-response correlation. Server echoes it in response.
type string Yes Message type (e.g., auth.phone, message.send, contact.list)
conversation_id string Durable events and mutation responses of a conversation stream The conversation whose stream seq belongs to; absent for the account stream
seq string Durable events and mutation responses Place in the event's stream, a decimal string
ok boolean Responses only true for success, false for failure. Present only in server responses.
data object No Payload. Structure depends on message type.
error object On failure Error details. Present only when ok is false.

When data is present it must be a JSON object with the shape required by the message type. Senders must omit an optional body rather than encode it as null; malformed bodies and null are rejected with invalid_format.

Type Naming

Message types are lowercase names in <domain>.<operation> form. Names use clear domain terms and complete operations rather than opaque abbreviations.

Request-Response Correlation

seq, message IDs and sync cursors are decimal strings. They must not be decoded as JSON numbers because their range can exceed JavaScript's exact integer range.

Response Format

Success without data:

{"id": "1", "type": "auth.logout", "ok": true}

Success with data:

{"id": "2", "type": "contact.list", "ok": true, "data": {"contacts": [...]}}

Failure:

{
  "id": "3",
  "type": "auth.phone",
  "ok": false,
  "error": {
    "code": "invalid_code",
    "message": "The code is wrong"
  }
}

Error Object

Field Type Required Description
code string Yes Machine-readable error code (snake_case)
message string Yes Human-readable error description
retry_after number No Seconds to wait before trying again; given with rate_limited when the wait is known

Error Codes

Code Description
invalid_token Token is invalid or expired
not_authenticated Operation requires authentication
user_not_found User does not exist
contact_not_found Contact not in contact list
contact_exists Contact already in contact list
session_not_found The persistent session named does not exist or is not the caller's
transfer_not_found The direct transfer named is unknown or over
transfer_expired The direct transfer was not carried in time
not_authorized Not authorized for this operation
invalid_format Invalid message format
rate_limited Too many requests, slow down
internal_error Internal server error
no_common_types Client and server share no negotiated message type
not_found Requested message or HTTP resource does not exist
conflict State changed since the supplied revision or an operation ID was reused for another command
invalid_state The command is not valid for the current message or actor
invalid_code The confirmation code is wrong
verification_expired The verification is unknown, expired, already used or out of attempts: a new code has to be requested
delivery_failed The server could not send the code right now; the request may be repeated later
not_supported The server does not serve this request, such as a phone number in a country it does not send to

HTTP Error Responses

The avatar and file HTTP APIs use the HTTP status code and the same structured error object as WebSocket responses:

{
  "ok": false,
  "error": {
    "code": "not_authenticated",
    "message": "Authentication required or invalid"
  }
}

HTTP error responses have Content-Type: application/json. They do not contain WebSocket-only id or type fields.

HTTP Resource Naming

HTTP paths use plural resource nouns. A concrete resource is selected by an ID or capability token, while me identifies the authenticated user's singleton resource: /avatars/{user_id}, /avatars/me, /files/{file_id} and /transfers/{transfer_token}, and a smiley's picture is /smileys/{pack_id}/{smiley_id}/{format}. Group/channel avatars are subordinate resources at /conversations/{conversation_id}/avatar. Multipart chunks are subordinate resources at /files/{file_id}/parts/{part_number}.

Timestamps

All timestamps use ISO 8601 / RFC 3339 format in UTC:

YYYY-MM-DDTHH:mm:ssZ

Example: "2024-01-15T14:30:00Z"