Skip to content

Business messages: answerable buttons (reply, interactive quick reply, list rows, template) in the Tab order - #569

Merged
gabrielhhaber merged 4 commits into
gabrielhhaber:mainfrom
reffehcsoibaf:feat/business-button-replies
Oct 21, 2026
Merged

gabrielhhaber merged 4 commits into
gabrielhhaber:mainfrom
reffehcsoibaf:feat/business-button-replies

Conversation

@reffehcsoibaf

Copy link
Copy Markdown
Contributor

What

The buttons of a business's message become real buttons under the message list, in the order of Tab, and tapping a reply button answers the business the way WhatsApp Web does. Until now these messages were only text with "options: ..." (and buttonsMessage was stored empty), so a screen-reader user could read the options but not answer them.

How it works

  • Which buttons: core/business_buttons.py reads them off the message the server serialized, in four shapes: dynamicReplyButtons (reply buttons of a plain message, the kind most bots send today), interactivePayload.buttons (interactive / native flow: quick_reply, cta_url, cta_copy, cta_call), hydratedButtons (template) and list (each row of a list message). They are kept with the message as businessButtons (websocket_client.py).
  • Window: ui/conversation_panel/business_buttons.py (a new mixin, not more lines in message_list.py) shows one wx.Button per entry in the existing buttons container. A reply is sent once per tap (a second tap while it is on its way does nothing, a failure is never retried by itself) and the result is spoken. A link opens, a code is copied, a phone number is spoken. Nothing is sent to the server for those three.
  • Server: new route POST /api/:session/reply-button/:messageId (api_patches/.../buttonReplyController.ts, added to the three file lists). It runs in the page and calls what WhatsApp Web itself calls when the button is tapped, read over CDP:
    • plain message: WAWebSendButtonsMsgReplyChatAction(message, button, chat) (a buttons_response);
    • interactive quick_reply: sendTextMsgToChat with the label, quoting the message and carrying selectedIndex / selectedId, then markInteractiveButtonClicked;
    • list row: a list_response with the row's title, description and id, quoting the list;
    • template: WA-JS's replyToButtonMessage.
      The id is validated, the index is bounded, the native error is never returned (it can carry a chat id or text), and nothing is retried: a send that threw may have reached the business.

Tested

Live, on a real account, with the code from this branch (setup_api.py build, the app's own POST /reply-button returned 200):

  • Reply buttons of a plain message ("Estou de acordo", "Residência"): the business continued its flow.
  • Interactive quick_reply (Mercado Pago, "Consultar dívida"): sent as a reply that quotes the message, the business answered and the button was marked as used.
  • List (Equatorial, 8 rows): the rows appear as buttons and the business accepted the answer.
  • NVDA: Tab from the message list reaches the buttons and they are read.

Automatic: tests/test_business_buttons.py (reading of every shape, what is not offered, the request contract, the one-tap rule, the stored field) and buttonReplyController.test.ts (12 tests; the in-page function with fake WhatsApp Web modules, the route's refusals). The translation, changelog, guide and API-patch sync tests pass.

Not tested live

  • Template buttons (hydratedButtons): no message of that kind was available. They go through WA-JS's replyToButtonMessage, covered by the unit test only.
  • Link, copy and call buttons of interactive messages: read from the payload and unit-tested; no conversation had one.
  • The buttons are stored when a message arrives or is loaded, so messages saved before this change do not get them.

Notes

  • New strings (4 keys) are in all 7 locales; changelog item in all 7; usage guide (Businesses section) and registry updated in all 7.
  • tests/test_call_audio_* and test_call_*echo* fail in my environment because livekit is not installed there; unrelated.

🤖 Generated with Claude Code

reffehcsoibaf and others added 4 commits October 21, 2026 08:43
…o e dizer o número

Os botões de resposta (mensagens simples, interativas e de modelo) são enviados
como o WhatsApp Web envia, por um endpoint novo reply-button; link, copiar e
ligar são resolvidos na janela. Strings e changelog nos 7 idiomas e guia de uso.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@gabrielhhaber
gabrielhhaber merged commit 65feccd into gabrielhhaber:main Oct 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants