Technical docs

Message Reactions

Public reference generated from tech docs/message-reactions.md.

Overview

Support reference for the current message feedback and reaction paths.

What the backend actually supports

- Feedback state now lives on the `messages` table itself: - `reaction` - `reaction_at` - `feedback_comment` - `feedback_comment_at` - `feedback_state_updated_at` - `reaction_by_*` - Accepted reactions are: - `like` - `dislike` - `null` to clear feedback - `feedback_comment` is only retained for `dislike`. - Clearing the reaction clears the entire feedback state.

Eligibility and validation

- Backend feedback is rejected for: - `operator` messages - `contact` messages - That means backend eligibility currently allows feedback on assistant-side `ai` and `bot` messages. - `feedback_comment` is capped at `500` characters.

Public webchat API

- Public webchat feedback route is: - `PUT /api/public/webchat/messages/{message_id}/feedback` - Accepted body: - `{ "reaction": "like" | "dislike" | null, "feedback_comment"?: string | null }` - The processor verifies that: - the public API key resolves an organization - the `webchat-token` resolves a webchat session/contact - the message belongs to a conversation accessible through that contact channel - The route returns the full updated webchat message object, not just the reaction value.

Current widget mismatch

- The widget client still calls: - `PUT /api/public/webchat/messages/{message_id}/reaction` - Widget body: - `{ "reaction": "like" | "dislike" | null }` - There is no matching `/reaction` route in the current public webchat router. - If contact-side reactions are failing in the shipped widget, this path mismatch is the first thing to check.

Widget-side behavior

- The widget only shows reaction buttons when: - `message.role === 'ai'` - It does not show them for: - `bot` - `operator` - Clicking the same reaction twice toggles it back to `null`. - The widget updates reaction state optimistically in local component state.

Propagation to Omni and the widget

- Public webchat feedback updates emit: - `conversation.message_updated` to organization websocket clients - Omni consumes that event and reads reaction fields from the updated message payload. - Omni renders feedback as read-only footer state on outgoing messages. - The widget listens for: - `webchat.message_updated` - But its websocket handler currently only patches: - `content` - `updated_at` - It does not reconcile websocket-delivered reaction, comment, or actor fields.

Internal chat feedback path

- Internal chat uses the organization route: - `PUT /api/organizations/{orgId}/conversations/{conversationId}/messages/{messageId}/feedback` - That flow emits: - `internal.message_updated` - Internal chat feedback also adds rate limiting for repeated changes on the same message.

Reporting API

- Aggregate webchat AI feedback stats are available from: - `GET /api/organizations/{orgId}/messages/stats` - Supported `types` query values are: - `total` - `likes` - `dislikes` - Those counts are scoped to: - `role = ai` - `channel = web_chat`

Start building your AI team