DEV Community

Nitin Suryawanshi
Nitin Suryawanshi

Posted on

Building a WhatsApp Interactive Button & List Message Handler in TypeScript

Interactive messaging is one of the most effective ways to increase user engagement and eliminate typing friction on WhatsApp. Rather than forcing users to type out responses like "1", "YES", or "MENU", the official Meta WhatsApp Cloud API supports interactive buttons (quick replies, call-to-action buttons) and scrollable list menus (up to 10 options).

In this tutorial, we will build a production-ready, type-safe interactive message handler in TypeScript that parses incoming interactive payloads and routes them into conversational flows.


Understanding WhatsApp Interactive Payloads

When a recipient taps an interactive button or list item, Meta delivers an inbound webhook payload where the message type is set to "interactive".

Inside the interactive object, you will receive either:

  1. button_reply: Contains the id and title of the clicked quick-reply button.
  2. list_reply: Contains the id, title, and optional description of the chosen list row.

Step 1: Defining TypeScript Interfaces

Let's define the strict typings for incoming interactive webhook events:

export interface WhatsAppInteractiveButtonReply {
  id: string;
  title: string;
}

export interface WhatsAppInteractiveListReply {
  id: string;
  title: string;
  description?: string;
}

export interface WhatsAppInteractiveMessage {
  from: string;
  id: string;
  timestamp: string;
  type: 'interactive';
  interactive: {
    type: 'button_reply' | 'list_reply';
    button_reply?: WhatsAppInteractiveButtonReply;
    list_reply?: WhatsAppInteractiveListReply;
  };
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Sending Interactive Quick-Reply Buttons

Here is how to construct and send an interactive button message using Axios and TypeScript:

import axios from 'axios';

interface ButtonPayload {
  to: string;
  bodyText: string;
  buttons: Array<{ id: string; title: string }>;
}

export async function sendInteractiveButtons({ to, bodyText, buttons }: ButtonPayload) {
  const url = `https://graph.facebook.com/v21.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`;

  const payload = {
    messaging_product: 'whatsapp',
    recipient_type: 'individual',
    to,
    type: 'interactive',
    interactive: {
      type: 'button',
      body: { text: bodyText },
      action: {
        buttons: buttons.map(btn => ({
          type: 'reply',
          reply: { id: btn.id, title: btn.title }
        }))
      }
    }
  };

  const response = await axios.post(url, payload, {
    headers: {
      Authorization: `Bearer ${process.env.WHATSAPP_CLOUD_API_TOKEN}`,
      'Content-Type': 'application/json'
    }
  });

  return response.data;
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Dispatching to Conversational CRM and AI Handlers

Once the interactive webhook arrives at your server, you should route it based on the action ID:

export async function handleInteractiveReply(msg: WhatsAppInteractiveMessage) {
  const customerPhone = msg.from;
  const replyType = msg.interactive.type;
  const actionId = replyType === 'button_reply' 
    ? msg.interactive.button_reply?.id 
    : msg.interactive.list_reply?.id;

  console.log(`Received action ${actionId} from ${customerPhone}`);

  switch (actionId) {
    case 'ACTION_BOOK_DEMO':
      // Move customer into 'Demo Scheduled' stage in CRM
      break;
    case 'ACTION_TALK_HUMAN':
      // Trigger human agent assignment
      break;
    case 'ACTION_FAQ':
      // Pass inquiry to AI Knowledge Base
      break;
    default:
      console.warn('Unhandled interactive ID:', actionId);
  }
}
Enter fullscreen mode Exit fullscreen mode

Enterprise Production Considerations

Managing raw button schemas, translation dictionaries, and state machines across hundreds of concurrent chats can quickly become complex.

Platforms like AI Soul provide a visual drag-and-drop conversational designer where interactive buttons, list menus, and AI fallbacks can be configured with zero boilerplate code. Incoming selections are automatically reflected inside the Conversational CRM and can trigger automated WhatsApp Drip Campaigns or AI Chatbot Solutions.


Conclusion

Interactive WhatsApp messages drastically improve completion rates compared to plain text replies. By modeling strict TypeScript contracts and decoupling interactive events from business logic, your integration remains reliable and maintainable.

Top comments (0)