support.message.received
A member sends a message into a support conversation.
The message body is not in the payload. Webhook deliveries are logged and
retried, and member text does not belong in a delivery log. Fetch it with GET /v1/support/conversations/{conversation_id}/messages.
When this fires
Every time a member sends an inbound message that lands in the support inbox — including the very first one, which also raises support.conversation.opened.
This is the workhorse of the family. If you are routing member questions into a helpdesk, an ops channel or an on-call rota, this is the event to subscribe to.
It does not fire when:
- The text was a recognised bot command, or an answer the bot was waiting for mid-setup.
- The member is blocked. Their messages are dropped without a trace in the inbox.
- The member has tripped the inbound rate limit. Excess messages are dropped silently rather than queued.
- The member edited an earlier message. The stored message is updated in place and no new event fires.
Required ability
support-conversation:view — token must carry this at mint time to subscribe an endpoint to this event.
Payload
{
"id": "evt_01HX...",
"type": "support.message.received",
"created_at": "2026-08-20T10:05:00Z",
"api_version": "2026-05-01",
"project_id": "prj_01HX...",
"data": {
"message_id": "smg_01HX...",
"conversation_id": "sup_01HX...",
"project_id": "prj_01HX...",
"subscriber_id": "usr_01HX...",
"type": "text",
"has_attachments": false
}
}Field reference
| Field | Type | Notes |
|---|---|---|
id | string ULID | Unique event id, prefixed evt_. Use for idempotent processing. |
type | string | Always support.message.received for this event. |
created_at | ISO 8601 timestamp | Server-side emission time. |
api_version | string | Webhook API contract version. |
project_id | string ULID | Project this event belongs to. |
data.message_id | string ULID | The stored message. |
data.conversation_id | string ULID | Thread the message belongs to. |
data.project_id | string ULID | Mirrors the envelope project_id. |
data.subscriber_id | string ULID | The member's project-scoped user id. |
data.type | string | One of text, photo, video, audio, voice, document, sticker, animation, location, contact. |
data.has_attachments | boolean | Whether the message carried media. Use it to decide whether a fetch needs to handle files. |
Caveats
- No body, no name, no file ids. Everything human-readable is behind the API on purpose. Telegram
file_idvalues are effectively credentials for downloading the file and are never sent in a webhook. - An album (several photos sent together) arrives as one event per part, each with its own
message_id. They share amedia_group_idvisible through the API, not in the payload. - A captioned photo has
type: "photo", and the caption is the message body — it is not a separate text message. - A caption that starts with
/is parsed as a bot command upstream and never reaches the inbox.
Related events
support.conversation.opened— fires alongside on the member's first message.support.message.sent— your side of the exchange.support.conversation.reopened— fires alongside when the message revives a resolved thread.- Support events overview — back to family overview.
How is this guide?