Skip to main content
When a contact taps a reply button on a message sent with POST /messages/buttons, or picks a row on a list sent with POST /messages/list, WSAPI delivers a message event that says which one they chose.
Interactive messages are in beta. See the caveats on sending them.

What arrives

How to use it

  • Route on the id, not on the text. buttonReply.id and listReply.id are the values you set, and they stay the same whatever the label says. Labels get reworded, translated and A/B-tested — the example above is a Spanish “Confirmar” for a button whose id is confirm. Matching on text breaks the first time someone edits the copy.
  • text is there for everything else. It is filled with the label or row title so that integrations reading only text — a chatbot, a helpdesk inbox, a log — still show something sensible. Do not rely on it for logic.
  • Correlate with replyTo.id. It is the id returned by POST /messages/buttons or POST /messages/list. Store that ID when you send, next to whatever the message is about — the appointment, order or ticket — and look it up when the reply arrives. A button id like confirm tells you what was chosen; replyTo.id tells you which appointment it was chosen for.
  • Only reply buttons and list rows produce events. url, copy and call buttons act on the contact’s device — open a link, copy a code, start a call — and nothing comes back to you.
  • Replies arrive inside the message event, so message has to be allowed in your event filters.

What can be absent

  • listReply.description is omitted when the row was sent without a description.
  • buttonReply.text and listReply.title come from the contact’s WhatsApp client. Expect them, but treat them as optional.
  • replyTo should always be present on a reply, since a reply is always to a message. Still, check for it rather than assume it: if it is missing, you know what was chosen but not for which message — fall back to the most recent open request in that chat, or ask again.

Make the handler idempotent

A contact can tap a button more than once, or scroll up and tap a button on an older message. Each tap is a separate event. Webhook deliveries can also be retried. Design for it:
  • Look up the state of the thing replyTo.id points to before acting. An appointment that is already confirmed should not be confirmed twice; one that was cancelled should not be confirmed at all.
  • Decide what a second, different answer means — for example, cancel after confirm — instead of letting the last event win by accident.
  • Deduplicate on eventId if your processing has side effects such as charges or outgoing notifications.

Example handler

Node.js
The db, appointment and booking objects stand for your own data layer. The point is the shape: find the record through replyTo.id, switch on the id, and check the current state before changing it.