response_url, so you can reply or update the original message.
The payloads are flat — action_id, value, and user sit at the top level. There is no wrapper object.
interaction.button_clicked
The
action_id from the button you made.The button’s
value, exactly as you sent it. An empty string if you set none.The button text at the time of the click.
A word-for-word copy of the
metadata you set on the message. An empty object if you set none.Who clicked.
Link buttons (any button with a
url) never send events. They just open a tab.interaction.form_submitted
Same base fields, with the answers invalues:
The form’s
form_id — the one you set, or the one we made if you left it out. It matches the event’s action_id.How values are typed
Every key is always there, even when empty. Your field mappings will not break on a missing path.
We check answers on our servers before sending them to you. If a check fails, the visitor sees the errors inline and you get nothing. So anything that reaches you already passed your
required, min, max, and options rules.Replying
Every event carries its ownresponse_url. The natural move is to swap the form for a confirmation:
Two fields that lie
Spot repeats withevent_id — it is the same across retries. See Receiving events.
Button state
After we accept a click, the group turns off and the clicked button shows as chosen — unless you setdisable_on_click: false. This state is saved on our side, so page reloads and other viewers all agree.
Buttons show as turned off when:
- The message is over 30 days old.
- A human has taken over the conversation.
- The conversation has passed its storage window.
Interactions do not turn on the typing dots by default.

