The WebSocket gateway is the live channel; REST is the audit trail. Every message saved through the gateway is also addressable via /chat/* endpoints — useful for admin panels, exports, and offline rendering.
History by chat
/chat/history/{chatId}JWTReturns every saved message for the conversation in chronological order. chatId formats:
customer:{email}— authenticated customer single-threadcustomer:{sessionId}:{email}— guest customer scoped by session{emailA}|{emailB}— staff-to-staff DM (sorted)- Anything provided by an agent when calling
sendMessagedirectly
curl https://appengine.appmint.io/chat/history/customer:[email protected] \
-H "orgid: my-org" -H "Authorization: Bearer <jwt>"
History by user
/chat/messages/{email}/{createdAfter?}JWTAll messages where the user appears as from or to. The optional createdAfter is an ISO timestamp for incremental sync.
| Field | Type | Description |
|---|---|---|
| email* | string | The email address whose messages you want. |
| createdAfter | string | Only return messages created after this ISO timestamp. Useful for pagination. |
Save a message
/chat/save/{chatId}JWTPersist a message without going through the socket. Emits chat-new-message on the internal event bus, which downstream listeners (CRM inbox, automations) consume.
{
"from": "[email protected]",
"to": "[email protected]",
"content": "Following up on our call.",
"type": "user",
"senderRole": "customer",
"sentTime": 1714000000000
}
Update a message
/chat/update/{chatId}JWTEdit a previously saved message (typically status updates: sent → delivered → read). The body must include messageId. Emits chat-update-message.
{
"messageId": "sk-abc",
"status": "read",
"readAt": "2026-04-25T12:34:56Z"
}
Live chat REST helper
/chat/live/{chatId}/{userId}JWTServer-side send path used by integrations that don't hold a Socket.IO connection (cron jobs, webhook handlers, automation actions). Posts the message into the chat as if a live client had sent it.
File uploads
/chat/upload/{chatId}/{userId}No authMultipart upload — files[]. The endpoint is publicly callable so unauthenticated widget uploads work; the server checks the chat config before accepting. Returns an array of stored file references that you then pass to chat-message (or sendMessage) as the files field.
Send a transcript by email
/chat/transcript/sendJWTRender the full conversation and email it. Used by widget "email me a copy" buttons.
{ "chatId": "customer:[email protected]", "email": "[email protected]" }
Get a single message
ChatService.getMessage(orgId, messageId) is also exposed internally and is what chat-update-message triggers. There's no dedicated GET /chat/message/:id REST endpoint at the time of writing — use /chat/history/{chatId} and filter client-side, or add the route if your admin needs single-message permalinks.
Active AI conversations
/chat/ai-activeJWTLists every conversation currently being handled by an AI assistant. The admin console uses this to show a "supervise AI" pane where agents can takeover-chat or assist-ai.
Searching messages
There is no dedicated full-text search endpoint in the chat module. For search, query the underlying chat_message collection through the data layer:
curl "https://appengine.appmint.io/data/chat_message?q=order+refund&limit=50" \
-H "orgid: my-org" -H "Authorization: Bearer <jwt>"
The exact filter syntax is described in Data layer / queries.