Messages
Messages belong to conversations. Visitors send messages via the REST API; operators reply from the admin dashboard. Messages sent via the REST API are automatically broadcast to connected WebSocket clients in real-time.
Messages support two content formats: plain text and rich text (Lexical). See Message Formats for details on contentFormat, contentHtml, and the Lexical JSON schema.
Send a Message
POST /api/v1/conversations/:id/messagesSends a message to a conversation. The conversation must be in pending or active status. The message is persisted and broadcast via WebSocket so operators see it immediately.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Message text (1–5,000 chars, trimmed). For rich text, this is a Lexical JSON string. |
contentFormat | string | No | "plain" (default) or "lexical". See Message Formats. |
cURL Example
curl -X POST https://api.deliverychat.online/api/v1/conversations/conv-uuid/messages \
-H "Authorization: Bearer dk_live_your_api_key" \
-H "X-App-Id: your-app-id" \
-H "X-Visitor-Id: 550e8400-e29b-41d4-a716-446655440000" \
-H "Origin: https://your-domain.com" \
-H "Content-Type: application/json" \
-d '{"content": "Hi, I need help with order #1234"}'Response — 201 Created
{
"message": {
"id": "msg-uuid",
"conversationId": "conv-uuid",
"senderId": "550e8400-e29b-41d4-a716-446655440000",
"content": "Hi, I need help with order #1234",
"contentFormat": "plain",
"contentHtml": null,
"createdAt": "2025-01-15T10:30:05.000Z"
}
}Errors
| Status | Error | When |
|---|---|---|
| 404 | not_found | Conversation not found or visitor is not a participant |
| 422 | conversation_not_active | Conversation is closed |
Get Message History
GET /api/v1/conversations/:id/messagesReturns paginated messages for a conversation. Soft-deleted messages are excluded.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Messages per page (1–100) |
offset | integer | 0 | Messages to skip |
cURL Example
curl "https://api.deliverychat.online/api/v1/conversations/conv-uuid/messages?limit=50&offset=0" \
-H "Authorization: Bearer dk_live_your_api_key" \
-H "X-App-Id: your-app-id" \
-H "X-Visitor-Id: 550e8400-e29b-41d4-a716-446655440000" \
-H "Origin: https://your-domain.com"Response — 200 OK
{
"messages": [
{
"id": "msg-uuid-1",
"conversationId": "conv-uuid",
"senderId": "550e8400-...",
"content": "Hi, I need help with order #1234",
"contentFormat": "plain",
"contentHtml": null,
"createdAt": "2025-01-15T10:30:05.000Z",
"editedAt": null
},
{
"id": "msg-uuid-2",
"conversationId": "conv-uuid",
"senderId": "operator-uuid",
"content": "{\"root\":{\"children\":[{\"children\":[{\"format\":1,\"text\":\"Sure!\",\"type\":\"text\",\"version\":1},{\"text\":\" Let me look into that.\",\"type\":\"text\",\"version\":1}],\"type\":\"paragraph\",\"version\":1}],\"type\":\"root\",\"version\":1}}",
"contentFormat": "lexical",
"contentHtml": "<p><b>Sure!</b> Let me look into that.</p>",
"createdAt": "2025-01-15T10:31:00.000Z",
"editedAt": null
}
],
"limit": 50,
"offset": 0
}Errors
| Status | Error | When |
|---|---|---|
| 404 | not_found | Conversation not found or visitor is not a participant |
Edit a Message
PATCH /api/v1/conversations/:id/messages/:messageIdEdits a message you sent. Subject to two constraints:
- Sender ownership — You can only edit your own messages
- 15-minute time window — Edits are only allowed within 15 minutes of the message’s creation time
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Updated message text (1–5,000 chars, trimmed). For rich text, this is a Lexical JSON string. |
contentFormat | string | No | "plain" (default) or "lexical". See Message Formats. |
cURL Example
curl -X PATCH https://api.deliverychat.online/api/v1/conversations/conv-uuid/messages/msg-uuid \
-H "Authorization: Bearer dk_live_your_api_key" \
-H "X-App-Id: your-app-id" \
-H "X-Visitor-Id: 550e8400-e29b-41d4-a716-446655440000" \
-H "Origin: https://your-domain.com" \
-H "Content-Type: application/json" \
-d '{"content": "Updated: I need help with order #5678"}'Response — 200 OK
{
"message": {
"id": "msg-uuid",
"conversationId": "conv-uuid",
"senderId": "550e8400-...",
"content": "Updated: I need help with order #5678",
"contentFormat": "plain",
"contentHtml": null,
"createdAt": "2025-01-15T10:30:05.000Z",
"editedAt": "2025-01-15T10:32:00.000Z"
}
}Errors
| Status | Error | When |
|---|---|---|
| 404 | not_found | Message not found or belongs to another conversation |
| 403 | forbidden | You are not the sender of this message |
| 422 | edit_window_expired | More than 15 minutes have passed since the message was sent |
Delete a Message
DELETE /api/v1/conversations/:id/messages/:messageIdSoft-deletes a message. Same constraints as edit: sender ownership and 15-minute window.
cURL Example
curl -X DELETE https://api.deliverychat.online/api/v1/conversations/conv-uuid/messages/msg-uuid \
-H "Authorization: Bearer dk_live_your_api_key" \
-H "X-App-Id: your-app-id" \
-H "X-Visitor-Id: 550e8400-e29b-41d4-a716-446655440000" \
-H "Origin: https://your-domain.com"Response — 200 OK
{
"success": true
}Errors
| Status | Error | When |
|---|---|---|
| 404 | not_found | Message not found or belongs to another conversation |
| 403 | forbidden | You are not the sender of this message |
| 422 | edit_window_expired | More than 15 minutes have passed since the message was sent |
15-Minute Edit/Delete Window
Time window rule
Messages can only be edited or deleted within 15 minutes of their createdAt timestamp. After this window closes, the message becomes immutable.
When the window has expired, the API returns:
{
"error": "edit_window_expired",
"message": "Message msg-uuid can no longer be modified. The 15-minute edit window expired at 2025-01-15T10:15:00.000Z."
}This rule applies equally to the REST API and WebSocket — both share the same service layer.