Send, edit, delete and react
Your app sends, edits and deletes messages, and adds reactions, as the signed-in user. Chat applies the same rules whatever your UI allows, so this guide also shows the errors to handle.
Let a user send a message with a reply and a mention, correct or delete it, react to it, and see a clear state when your backend has archived the conversation.
Prerequisites
Section titled “Prerequisites”- A
ChatUserClient. See Get the user’s Chat token. - The user is a member of the conversation. Chat does not let a user write into a conversation they have not joined.
messages.sendmessages.updateUser scope: chat:access1. Send
Section titled “1. Send”messages.send(conversationId, { body }) needs messages.send and membership. The body can be up to 10,000 characters, otherwise you get body_too_long. A message needs a body or an attachment. Sending is limited to 30 messages per 10 s per user.
Add reply_to_message_id to reply. It must name a message of the same conversation, or you get invalid_reply. Add mentioned_user_ids to mention people. Chat records only the ones that are active members of the conversation.
A user cannot send a SYSTEM message: that is system_message_not_allowed and belongs to your backend. Attachments are references (file_id, name, mime_type, size); Chat stores no files. You can send at most 10 attachments per message.
2. Edit and delete
Section titled “2. Edit and delete”The author edits or deletes with messages.update. A moderator holding messages.delete can edit or delete anyone’s message. Without either you get missing_capability. An edited message has status: 'EDITED'. A deleted message leaves a tombstone.
3. React
Section titled “3. React”addReaction and removeReaction take the emoji. Reactions need membership. Machine clients cannot react.
4. Handle an archived conversation
Section titled “4. Handle an archived conversation”When your backend archives a conversation, sending answers 422 conversation_archived. Show the thread as read-only and disable the composer.
import { ChatForbiddenError, ChatUnprocessableError, type ChatMessage } from '@central-code-station/ccs-chat-user-client';import { chat } from './fe-guide-context';
export async function replyToClient(conversationId: string, replyTo: string): Promise<ChatMessage | null> { try { return await chat.messages.send(conversationId, { body: 'Great session, John. See you Thursday at 9!', reply_to_message_id: replyTo, mentioned_user_ids: ['client-john'], }); } catch (error) { if (error instanceof ChatUnprocessableError && error.code === 'conversation_archived') { return null; // your backend archived it: show the thread as read-only } throw error; }}
export async function editOrDelete(conversationId: string, message: ChatMessage, mine: boolean): Promise<void> { try { if (mine) await chat.messages.edit(conversationId, message.message_id, 'Moved to 10:00'); else await chat.messages.delete(conversationId, message.message_id); // needs messages.delete } catch (error) { if (error instanceof ChatForbiddenError && error.code === 'missing_capability') return; // hide the control next time throw error; }}
export async function react(conversationId: string, messageId: string): Promise<void> { await chat.messages.addReaction(conversationId, messageId, '👍'); await chat.messages.removeReaction(conversationId, messageId, '👍');}Verify
Section titled “Verify”Send a message from one user. It appears in messages.list for the other member. Edit it and the list shows status: 'EDITED'. Archive the conversation from your backend and send again to see the 422.
Troubleshooting
Section titled “Troubleshooting”| You see | Cause | Fix |
|---|---|---|
403 missing_capability on send |
The role lacks messages.send in this application. |
A tenant administrator grants it. |
403 not_conversation_member |
The user is not a member of the conversation. | Add the user from your backend, or join a PUBLIC channel. |
404 not_found on edit or react |
The message is deleted or belongs to another conversation. | Reload the thread. |
429 rate_limited |
Too many sends. | Wait retryAfterSeconds on the ChatRateLimitedError. |