Guides
Retention and ephemeral messages
Expiration is a field on every message. Channel and forum default to persistent. Integrators own who may change modes.
Expiration is a field on every message (expirationMode, expiresAt), not a separate type.
persistent: noexpiresAtafter_duration:expiresAt = now + expiresInMsafter_read:expiresAtis unset at send; the first recipientmarkReadarms it
Who may choose a mode is integrator-owned. Safe defaults keep messages persistent unless a type policy, conversation policy, or legal sender override says otherwise.
Type defaults
| Type | Default mode | Sender override | Conversation policy |
|---|---|---|---|
direct | persistent (global) | allowed | no |
group | persistent (global) | allowed | yes |
channel | persistent | off | yes |
forum | persistent | off | yes |
A 24h or after-read send on a channel or forum is rejected, not coerced to persistent, until policy allows it.
Conversation overrides live on columns, not JSON metadata. Cleanup of expired messages must not delete moderation jobs, results, audit events, push intents, or push jobs.
Expired bubbles in clients should show the same deleted placeholder whether the update arrived as message.updated, message.deleted with reason: "expired", or a local timer. Tombstone events remain authoritative.