Conversations
Managing customer conversations
Conversations
A conversation is a thread of messages between a visitor and your support team.
Conversation Lifecycle
OPEN → PENDING → RESOLVED → CLOSED
↓
SNOOZED
Statuses
| Status | Description |
|---|---|
| open | Active conversation requiring attention |
| pending | Awaiting customer response |
| snoozed | Temporarily hidden, will reopen at set time |
| resolved | Issue addressed, can be reopened |
| closed | Permanently closed |
Viewing Conversations
Dashboard
Navigate to Support > Inbox to see all conversations.
Filtering
Filter conversations by:
- Status (Open, Pending, Resolved, Closed)
- Assignee
- Inbox
- Tags
- Date range
Search
Search across conversations:
- Visitor name/email
- Message content
- Tags
- Custom attributes
API Operations
List Conversations
const response = await fetch('/api/support/conversations', {
headers: {
'X-API-Key': 'your-api-key',
},
});
const { data, meta } = await response.json();Query parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status |
inboxId | string | Filter by inbox |
assigneeId | string | Filter by assignee |
visitorId | string | Filter by visitor |
page | number | Page number |
limit | number | Items per page |
Get Conversation
const response = await fetch('/api/support/conversations/{conversationId}', {
headers: {
'X-API-Key': 'your-api-key',
},
});
const { data } = await response.json();Response:
{
data: {
id: 'conv-123',
status: 'open',
inboxId: 'inbox-123',
visitor: {
id: 'visitor-123',
name: 'John Doe',
email: 'john@example.com'
},
assignee: {
id: 'user-123',
name: 'Support Agent'
},
messages: [
{
id: 'msg-1',
type: 'visitor',
content: 'Hi, I need help',
createdAt: '2024-01-15T10:00:00Z'
},
{
id: 'msg-2',
type: 'agent',
content: 'How can I help?',
createdAt: '2024-01-15T10:05:00Z',
author: { id: 'user-123', name: 'Support Agent' }
}
],
tags: ['billing', 'urgent'],
createdAt: '2024-01-15T10:00:00Z',
updatedAt: '2024-01-15T10:05:00Z'
}
}Reply to Conversation
const response = await fetch('/api/support/conversations/{conversationId}/reply', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
message: 'Thanks for reaching out! Let me help you with that.',
type: 'reply' // 'reply' | 'note'
}),
});Add Internal Note
const response = await fetch('/api/support/conversations/{conversationId}/reply', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
message: 'Customer seems confused about pricing. Escalate to sales?',
type: 'note'
}),
});Internal notes are only visible to your team.
Assign Conversation
const response = await fetch('/api/support/conversations/{conversationId}/assign', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
assigneeId: 'user-456'
}),
});Update Status
const response = await fetch('/api/support/conversations/{conversationId}', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
status: 'resolved'
}),
});Snooze Conversation
const response = await fetch('/api/support/conversations/{conversationId}/snooze', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
until: '2024-01-16T09:00:00Z'
}),
});Add Tags
const response = await fetch('/api/support/conversations/{conversationId}/tags', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
tags: ['billing', 'urgent']
}),
});Remove Tag
const response = await fetch('/api/support/conversations/{conversationId}/tags/{tagId}', {
method: 'DELETE',
headers: {
'X-API-Key': 'your-api-key',
},
});Message Types
Text Message
{
type: 'text',
content: 'Hello, how can I help?'
}Attachment
{
type: 'attachment',
content: 'Here is the document you requested.',
attachments: [
{
name: 'invoice.pdf',
url: 'https://...',
type: 'application/pdf',
size: 102400
}
]
}Card/Rich Message
{
type: 'card',
content: {
title: 'Order #12345',
description: 'Your order has been shipped',
actions: [
{ label: 'Track Package', url: 'https://...' },
{ label: 'View Order', action: 'view_order' }
]
}
}Conversation Events
Subscribe to real-time events:
// WebSocket connection
const ws = new WebSocket('wss://api.usetransactional.com/support/conversations/live');
ws.onmessage = (event) => {
const { type, data } = JSON.parse(event.data);
switch (type) {
case 'conversation.created':
console.log('New conversation:', data);
break;
case 'message.received':
console.log('New message:', data);
break;
case 'conversation.updated':
console.log('Conversation updated:', data);
break;
}
};Webhooks
Configure webhooks for conversation events:
const response = await fetch('/api/support/webhooks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
url: 'https://your-server.com/webhook',
events: [
'conversation.created',
'conversation.assigned',
'conversation.resolved',
'message.received'
]
}),
});Webhook Payload
{
"event": "message.received",
"timestamp": "2024-01-15T10:00:00Z",
"conversation": {
"id": "conv-123",
"status": "open"
},
"message": {
"id": "msg-123",
"type": "visitor",
"content": "I need help with billing"
},
"visitor": {
"id": "visitor-123",
"email": "john@example.com"
}
}Canned Responses
Save time with pre-written responses:
Create Canned Response
const response = await fetch('/api/support/canned-responses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'your-api-key',
},
body: JSON.stringify({
title: 'Greeting',
shortcut: '/hello',
content: 'Hi {{visitor.name}}! Thanks for reaching out. How can I help you today?'
}),
});Using Variables
Available variables in canned responses:
| Variable | Description |
|---|---|
{{visitor.name}} | Visitor's name |
{{visitor.email}} | Visitor's email |
{{agent.name}} | Current agent's name |
{{company.name}} | Company name |
Automation Rules
Automate common tasks:
Auto-Assignment
{
trigger: 'conversation.created',
conditions: [
{ field: 'visitor.plan', operator: 'equals', value: 'enterprise' }
],
actions: [
{ type: 'assign', assigneeId: 'priority-team-id' },
{ type: 'addTag', tag: 'enterprise' }
]
}Auto-Reply
{
trigger: 'message.received',
conditions: [
{ field: 'message.content', operator: 'contains', value: 'refund' }
],
actions: [
{ type: 'reply', message: 'I see you have a question about refunds. Let me connect you with our billing team.' },
{ type: 'addTag', tag: 'refund-request' }
]
}Analytics
Conversation Metrics
const response = await fetch('/api/support/analytics/conversations', {
headers: {
'X-API-Key': 'your-api-key',
},
});
const { data } = await response.json();Response:
{
data: {
totalConversations: 500,
openConversations: 25,
resolvedToday: 45,
avgFirstResponseTime: 120, // seconds
avgResolutionTime: 3600, // seconds
csat: 4.5
}
}Next Steps
- Visitors - Managing visitors
- Companies - Company management
- API Reference - Full API documentation
On This Page
- Conversation Lifecycle
- Statuses
- Viewing Conversations
- Dashboard
- Filtering
- Search
- API Operations
- List Conversations
- Get Conversation
- Reply to Conversation
- Add Internal Note
- Assign Conversation
- Update Status
- Snooze Conversation
- Add Tags
- Remove Tag
- Message Types
- Text Message
- Attachment
- Card/Rich Message
- Conversation Events
- Webhooks
- Webhook Payload
- Canned Responses
- Create Canned Response
- Using Variables
- Automation Rules
- Auto-Assignment
- Auto-Reply
- Analytics
- Conversation Metrics
- Next Steps