Webhook event payloads
This page documents the payload schema for each webhook event type. All payloads include the base fields (event_type, request_id, session_id, external_session_id, integration_id, desk_id, channel_type, account_id, account_slug, and context), plus the timestamp carried by the event itself. The examples below show a representative subset of the base fields rather than repeating all of them.
AI agent message
Event type: message:brain_send
Sent when the AI agent responds to the user. The output.responses array contains one or more response objects.
{
"event_type": "message:brain_send",
"request_id": "req-123",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"output": {
"responses": [
{
"type": "text",
"text": "Hello! How can I help you today?",
"options": [
{
"label": "Check Order",
"text": "I want to check my order"
},
{
"label": "Support",
"text": "I need support"
}
]
}
]
}
}
Response types
The output.responses array can contain multiple response objects. Each response has a type field and an action_id. The action_id identifies the dialog action that produced the response. It is stable across sessions and useful for correlating a response with the dialog node that emitted it.
| Type | Description |
|---|---|
text | Plain text message, optionally with quick reply options. |
image | Image attachment. |
video | Video attachment. |
file | File attachment. |
url | A URL for your system to open or render. |
carousel | Multiple cards with buttons. |
webview | Open a webview. |
survey | A survey to present to the user. |
handover | Transfer to a human agent. |
close | The AI agent ended the conversation. |
pause | A delay before the next response, optionally showing a typing indicator. |
whatsapp_flow | A WhatsApp Flow. Only emitted by agents built for WhatsApp. |
Moveo may also emit the internal types replay and reminder. They carry no message for the user. Ignore any response type you do not handle rather than treating it as an error.
Text response
{
"type": "text",
"text": "Here's your order status.",
"options": [
{
"label": "Track Order",
"text": "Track my order"
}
]
}
| Field | Type | Description |
|---|---|---|
type | string | "text" |
text | string | The message text. |
options | array | Optional quick reply buttons. |
options[].label | string | Button label displayed to the user. |
options[].text | string | The value associated with this option. Your system is responsible for handling the button click and sending this text back as a user message if needed. |
Image response
{
"type": "image",
"url": "https://example.com/image.jpg",
"name": "Product Image"
}
| Field | Type | Description |
|---|---|---|
type | string | "image" |
url | string | Image URL. |
name | string | Optional image name/caption. |
Video response
{
"type": "video",
"url": "https://example.com/video.mp4",
"name": "Tutorial Video",
"size": 5242880
}
URL response
{
"type": "url",
"url": "https://example.com/order/12345"
}
| Field | Type | Description |
|---|---|---|
type | string | "url" |
url | string | The URL to open or render. |
File response
{
"type": "file",
"url": "https://example.com/document.pdf",
"name": "Invoice.pdf",
"size": 102400
}
| Field | Type | Description |
|---|---|---|
type | string | "file" |
url | string | File download URL. |
name | string | Filename. |
size | integer | File size in bytes (optional). |
Carousel response
{
"type": "carousel",
"cards": [
{
"title": "Product A",
"subtitle": "$29.99",
"media": {
"type": "image",
"url": "https://example.com/product-a.jpg"
},
"buttons": [
{
"type": "postback",
"label": "Buy Now",
"value": "Buy Product A"
},
{
"type": "url",
"label": "Learn More",
"url": "https://example.com/product-a"
}
]
}
]
}
| Field | Type | Description |
|---|---|---|
type | string | "carousel" |
cards | array | Array of card objects. Between 1 and 6. |
cards[].title | string | Card title. |
cards[].subtitle | string | Card subtitle. |
cards[].media | object | Card image or video (optional). |
cards[].media.type | string | "image" or "video". |
cards[].media.url | string | Media URL. |
cards[].buttons | array | Action buttons. |
cards[].buttons[].type | string | "postback", "url", "webview", "phone", or "event". |
cards[].buttons[].label | string | Button text. |
cards[].buttons[].url | string | URL for url and webview buttons. |
cards[].buttons[].value | string | Payload for postback and event buttons, or the phone number for phone buttons. |
cards[].buttons[].trigger_node_id | string | Dialog node that a webview button triggers. |
cards[].buttons[].height | string | Webview height for webview buttons. |
cards[].buttons[].auto_open | boolean | Whether a webview button opens automatically. |
cards[].default_action | object | Optional button applied when the card itself is tapped. |
Handover response
Signals that the AI agent is transferring the conversation to a human agent. The AI agent stops replying from this point on.
{
"type": "handover",
"metadata": {
"zendesk_department_id": "support"
}
}
| Field | Type | Description |
|---|---|---|
type | string | "handover" |
metadata | object | Optional flat key-value map configured on the dialog action, used to route the transfer. |
department_id | string | Deprecated. A target department set on older agents, still sent where it was configured. Prefer metadata. |
Any message shown to the user before a transfer arrives as a separate text response, not as a field on this one.
Close response
Signals that the AI agent ended the conversation.
{
"type": "close"
}
Pause response
A deliberate delay before the next response, used to pace a multi-part reply.
{
"type": "pause",
"duration": 2,
"show_typing": true
}
| Field | Type | Description |
|---|---|---|
type | string | "pause" |
duration | integer | Delay in seconds. |
show_typing | boolean | Whether to show a typing indicator for the duration. |
Webview response
{
"type": "webview",
"url": "https://example.com/form",
"name": "Order form",
"label": "Fill out form",
"height": "full",
"auto_open": false
}
| Field | Type | Description |
|---|---|---|
type | string | "webview" |
url | string | Webview URL. |
name | string | Webview name. |
label | string | Button label. |
height | string | "full", "tall", "compact", or "new_window". |
auto_open | boolean | Whether the webview should open without the user tapping the button. |
A survey response has the same fields as a webview response and points at a survey URL.
Human agent message
Event type: message:send
Sent when a human agent from Moveo's live chat replies to the user.
{
"event_type": "message:send",
"request_id": "req-456",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"from": {
"agent_id": "agent-123",
"agent_name": "Sarah Johnson",
"agent_avatar": "https://example.com/avatars/sarah.jpg",
"team_id": "support-team"
},
"to": {
"user_id": "user-789"
},
"body": {
"text": "Hi! I'm Sarah from support. How can I help you?",
"attachments": []
}
}
| Field | Type | Description |
|---|---|---|
from.agent_id | string | Agent's unique identifier. |
from.agent_name | string | Agent's display name. |
from.agent_avatar | string | URL to agent's avatar (optional). |
from.team_id | string | Agent's team/department ID (optional). |
to.user_id | string | Target user ID. |
body.text | string | Message text. |
body.attachments | array | Attachments (same format as input attachments). |
Typing indicator
Event type: message:compose
Sent when someone starts or stops typing.
{
"event_type": "message:compose",
"request_id": "req-789",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"author_id": "agent-123",
"author_name": "Sarah Johnson",
"author_type": "agent",
"action": "start"
}
| Field | Type | Description |
|---|---|---|
author_id | string | ID of the person typing. |
author_name | string | Name of the person typing. |
author_type | string | "agent" or "brain". |
action | string | "start" or "stop". |
Message read
Event type: message:read
Sent when messages are marked as read.
{
"event_type": "message:read",
"request_id": "req-101",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"author_type": "agent"
}
| Field | Type | Description |
|---|---|---|
author_type | string | Who marked messages as read: "agent", "brain", or "visitor". |
Message delivered
Event type: message:delivered
Sent when messages are confirmed delivered.
{
"event_type": "message:delivered",
"request_id": "req-102",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"author_type": "brain"
}
Member join
Event type: conversation:member_join
Sent when an agent joins the conversation.
{
"event_type": "conversation:member_join",
"request_id": "req-103",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"author_id": "agent-123",
"author_name": "Sarah Johnson",
"author_type": "agent"
}
Member leave
Event type: conversation:member_leave
Sent when an agent leaves the conversation.
{
"event_type": "conversation:member_leave",
"request_id": "req-104",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"author_id": "agent-123",
"author_name": "Sarah Johnson",
"author_type": "agent"
}
Conversation closed
Event type: conversation:closed
Sent when a conversation is marked as resolved.
{
"event_type": "conversation:closed",
"request_id": "req-105",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"status": "resolved",
"agent_id": "agent-123",
"agent_name": "Sarah Johnson"
}
Conversation reopened
Event type: conversation:reopened
Sent when a resolved conversation is reopened.
{
"event_type": "conversation:reopened",
"request_id": "req-106",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
}
}
Session closed
Event type: session:closed
Sent when a session is explicitly closed.
{
"event_type": "session:closed",
"request_id": "req-107",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
},
"timestamp": 1789084800000,
"status": "closed"
}
Session expired
Event type: session:expired
Sent when a session expires due to inactivity timeout.
{
"event_type": "session:expired",
"request_id": "req-108",
"session_id": "sess-456",
"external_session_id": "your-session-789",
"integration_id": "intg-001",
"desk_id": "desk-456",
"context": {
"user": {
"user_id": "user-789"
}
}
}