Skip to main content

Messages and delivery

A message​

FieldMeaning
idInteger, increasing. Use it as the cursor (after_id) and for ack.
to_session, from_sessionRecipient and sender names.
from_principalThe principal of the sender's token. Set by the bus, not by the sender.
token_idId of the token that sent it (not the token).
bodyText, 1 byte to 16 KiB (UTF-8).
thread_idOptional string from the sender, or null.
created_at, acked_atMilliseconds since the epoch. acked_at is null until acked.

Delivery rules​

  • At-least-once. A message stays in the recipient's inbox until it is acked. A reader can see the same message again, for example after a restore. Handle duplicates by id.
  • Ack is explicit. ack marks ids as handled for a session you own. It is idempotent: an already-acked id keeps its first acked_at.
  • Unacked mail is never pruned. Only acked messages older than 7 days (by acked_at) are deleted. Pruning runs when serve starts and then every hour.
  • Reading is a cursor. inbox returns messages with id > after_id, oldest first, at most 50 per call. By default it returns only unacked messages; include_acked: true includes acked ones.
  • Ownership. You can only read, ack, or send as a session your principal owns (NOT_OWNER otherwise).

Limits​

LimitValueError
Message body16 KiBBODY_TOO_LARGE
Unacked messages per recipient1000INBOX_FULL on send; broadcast skips that recipient
Messages per inbox call50(capped)
HTTP request body64 KiBHTTP 413
Stale session7 days without register/inboxhidden from list_sessions, skipped by broadcast

Durability​

The store is SQLite in WAL mode with synchronous=NORMAL. A process crash (including kill -9) loses no committed message; the end-to-end test checks this. A power loss can lose the last few transactions. This is an accepted trade-off. See Data model and durability.