A message is one entry in a conversation. It's saved on the server, so it survives reconnects, restarts, and the sender closing their laptop.
Messages are usually sent from your app with chat.sendMessage(), after
it connects with a chat token. Every member who is connected gets it right
away, and members who were offline see it in the history later.
What happens when Alice sends a message
1. alice's app: sendMessage("Hello")
2. Livqeno saves it, and gives it an id and its place in the order
3. sendMessage() resolves with the saved message → "it's stored"
4. every connected member (alice too) gets a `message` event
5. bob, offline, sees it later in the message history
6. your backend gets a `message.created` webhook, if you set one up
The server decides the order
Everyone, including the sender, shows the message the server saved. That's why sending works in two parts:
sendMessage()resolves with the saved message. This means "it's stored".- The sender also gets the
messageevent, like everyone else. Render from this event.
This way, two devices with different clocks still agree on the order.
Types
type ChatMessageType = 'text' | 'system' | 'event' | 'attachment';| Type | Who can send it | Use it for |
|---|---|---|
text | Your app (the default) | A normal message from a user. |
attachment | Your app | A message with a file. See Attachments. |
system | Your backend only | Messages your server posts, not a user. |
event | Your backend only | Messages your server posts, not a user. |
See Messages for the details of each type.
No double posts on retry
On a bad network, an app may send the same message twice (it didn't hear
back, so it tries again). To stop duplicates, pass a clientMessageId, a
unique id your app makes for each message.
In your browser app:
await chat.sendMessage({
text: 'Hello everyone',
clientMessageId: crypto.randomUUID(),
});The server removes duplicates using (conversation, sender, clientMessageId).
The response tells you if it was a new send or a repeat. A duplicate also
isn't counted twice toward your usage.
Editing and deleting
- Edit: changes the text and fires
messageUpdated. - Delete: a soft delete. The message stays in place, its content is
removed, and
messageDeletedfires. History and the audit trail stay intact, so a conversation never has confusing gaps.
Threads are flat
A thread is a set of replies to one message. A reply to a reply goes into the same thread as its parent. There's no nesting, so threads stay easy to follow.
Limits
| Limit | Default |
|---|---|
| Text | 4000 characters |
| Metadata | 4096 bytes |
Going over either fails with RAVEN_MESSAGE_TOO_LARGE. This is a different
error from the attachment limit, so you know which one you hit.
Next steps
- Messages: send, edit, and delete from your app.
- Message history: load older messages.
- Threads · Limits & quotas