Skip to content

Ordering and limits

Events are not ordered, and the same change can reach a client more than once: twice on the socket, or once on the socket and once in a catch-up. Three rules make every copy safe to apply: deduplicate on id, keep the higher seq, and move pointers forward only.

Every event arrives in the envelope {type, id, ts, data}. id is a UUIDv7. Drop an event whose id you have already handled. With presence.fanout on, presence.changed can arrive twice, on the peer’s presence channel and on your own channel, with the same id.

The frame remembers the last 1000 event ids.

message.created, message.updated and conversation.updated carry the seq of their Message or ConversationSummary, and catch-up rows carry it too. When two copies of the same message or inbox row meet, keep the one with the higher seq. Never replace a copy with one of a lower seq, whether it comes from an event or a catch-up.

  • A message’s seq is its place in its conversation’s sync order.
  • An inbox row’s seq is the viewer’s inbox seq for that row.

read.updated and delivered.updated carry a message id: last_read_message_id or last_delivered_message_id. Read it as “everything up to this message”. Message ids are UUIDv7 and sort by creation as strings, so mark each of your own messages with an id less than or equal to the pointer, and never unmark one. A late event with an older pointer then changes nothing.

The participants pointers in a thread catch-up work the same way.

seq counts every change, including ones you never see: a message the other side deleted for themselves, a send that was dropped silently. Never infer missing data from a gap. Ask the catch-up routes for what changed instead.

The other events carry no seq: read.updated, delivered.updated, typing, presence.changed, photos.updated, call.ringing, call.updated, call.capture, purchase.updated and session.revoked. Deduplicate them on id. For calls and purchases, the recovery calls give the current state after a gap.

Limit Value
Subscriptions per socket 200
Presence subscriptions the frame keeps 100
Socket lifetime 24 hours
Keep-alive from AppSync every 60 s
Session token lifetime 900 s
Presence pass lifetime 1 hour
Events per publish 5, each under 240 KB
GET /v1/conversations?changed_since page limit at most 50
GET /v1/conversations/{id}/changes page limit 1 to 200, default 100
Typing send at most every 3 s, show for 5 s
  • seq only compares copies of the same message or the same inbox row. Events of different types have no order between them.
  • seq does not tell you what is missing, only which copy is newer.
  • Presence, typing and settings changes take no seq. Recover presence by reloading it, as presence subscriptions explains.