Messages API
Manage messages within tickets—both customer replies and internal notes.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /tickets/:ticket_id/messages | List messages |
| POST | /tickets/:ticket_id/messages | Create message |
| GET | /tickets/:ticket_id/messages/:id | Get message |
| DELETE | /tickets/:ticket_id/messages/:id | Delete message |
List Messages
GET /api/v1/tickets/:ticket_id/messagesQuery Parameters
| Parameter | Type | Description |
|---|---|---|
include_internal | boolean | Include internal notes (default: true) |
Response
{ "data": [ { "id": "msg-uuid-1", "body": "I cannot login to my dashboard since this morning.", "body_html": "<p>I cannot login to my dashboard since this morning.</p>", "is_internal": false, "direction": "inbound", "sender": { "name": "John Doe", "email": "john@example.com" }, "attachments": [ { "id": "att-uuid-1", "filename": "screenshot.png", "content_type": "image/png", "size": 245678, "url": "https://..." } ], "created_at": "2024-01-15T10:30:00Z" }, { "id": "msg-uuid-2", "body": "Thanks for reaching out. Let me check your account...", "is_internal": false, "direction": "outbound", "sender": { "name": "Jane Agent", "email": "jane@company.com" }, "attachments": [], "created_at": "2024-01-15T11:15:00Z" } ]}Create Message
POST /api/v1/tickets/:ticket_id/messagesRequest Body
{ "body": "Thanks for reaching out. I've reset your password...", "is_internal": false, "send_email": true}| Field | Type | Required | Description |
|---|---|---|---|
body | string | Yes | Message content (plain text or HTML) |
is_internal | boolean | No | Internal note if true (default: false) |
send_email | boolean | No | Send email notification (default: true for public) |
Response
{ "data": { "id": "msg-uuid-3", "body": "Thanks for reaching out. I've reset your password...", "is_internal": false, "direction": "outbound", "sender": { "name": "Jane Agent", "email": "jane@company.com" }, "email_sent": true, "created_at": "2024-01-15T11:30:00Z" }}Internal Notes
Create an internal note (not visible to customers):
{ "body": "Checked the logs - looks like a password issue.", "is_internal": true}Internal notes:
- Are visible only to team members
- Never send emails
- Appear differently in the UI
- Are included in the activity timeline
Get Message
GET /api/v1/tickets/:ticket_id/messages/:idResponse
Full message object:
{ "data": { "id": "msg-uuid-1", "body": "...", "body_html": "...", "is_internal": false, "direction": "inbound", "sender": { ... }, "attachments": [ ... ], "email_message_id": "<msg-id@mail.example.com>", "created_at": "2024-01-15T10:30:00Z" }}Delete Message
DELETE /api/v1/tickets/:ticket_id/messages/:idResponse
204 No ContentAttachments
Upload Attachment
Attachments are uploaded separately and referenced in messages:
POST /api/v1/attachmentsContent-Type: multipart/form-data
file: <binary>Response
{ "data": { "id": "att-uuid", "filename": "document.pdf", "content_type": "application/pdf", "size": 123456, "url": "https://..." }}Include in Message
Reference attachments when creating a message:
{ "body": "Please see the attached document.", "attachment_ids": ["att-uuid-1", "att-uuid-2"]}Email Integration
Inbound Emails
When emails arrive at connected mailboxes:
- New sender → new ticket with first message
- Reply to existing → new message on that ticket
- Attachments are extracted and stored
- HTML is preserved, plain text version generated
Outbound Emails
When send_email: true:
- Message is sent via connected mailbox
- Proper threading headers are added
- Email status is tracked (
email_sent: true/false)
Message Direction
| Direction | Meaning |
|---|---|
inbound | From customer (via email or portal) |
outbound | From team member to customer |
Internal notes don’t have a direction—they’re internal only.
Error Codes
| Code | Description |
|---|---|
TICKET_NOT_FOUND | Ticket doesn’t exist |
MESSAGE_NOT_FOUND | Message doesn’t exist |
EMPTY_BODY | Message body is required |
EMAIL_SEND_FAILED | Failed to send email |
ATTACHMENT_NOT_FOUND | Referenced attachment doesn’t exist |