Skip to main content
Six event types can reach your webhook. Route on the X-MyAIChatbot-Event header or the body’s event field — they always match. Every payload carries api_version (currently "2026-07-01") and a true/false test.

message.created

The main event. A visitor, member, or operator said something.
conversation.channel
string
widget, public_page, or internal.
conversation.routing_state
string
bot or taken_over. Once it is taken_over, you cannot post into this conversation.
conversation.metadata
object
Answers the visitor gave before the chat started, keyed by field name. Empty if you collect none.
message.seq
number
A per-conversation counter that only goes up. Sort by this, not by arrival time.
message.sender_type
string
visitor, member, bot, operator, or system.
message.text
string
The blocks flattened into plain text. Handy, and usually all you need.
response_url
string | null
Where to POST your reply. null if the platform is set up wrong.

interaction.button_clicked

A flat payload with action_id, value, and label at the top level. See Interactions for the full details.
event and type carry the same dotted name. type is there for tools that cannot map nested fields.

interaction.form_submitted

form_id is the form’s id — the one you set, or the one we made if you left it out. See Interactions for how values are typed.

conversation.handoff

An operator took over and pressed Send transcript to backend. It exists so your CRM can catch up. There is no response_url — on purpose, because the bot cannot speak in a conversation a human now owns.
transcript
array
Every message from slice_from on — the human era only, flattened to plain text.
The button can be pressed again. Each press re-sends the whole slice with a fresh event_id, so compare slice_from and slice_to.

webhook.verify

Sent when you press Verify. Send the challenge back. Never retried, and has no response_url. See Webhooks.

webhook.test

Sent by the Test webhook button. Shaped just like message.created so your real handler runs, but with a fake conversation, test: true, and no response_url.
Whatever you return is parsed and shown back to you — including any problems — without touching a real conversation.
Guard anything you cannot undo behind if (event.test) return. Both webhook.verify and webhook.test set it.