Skip to main content
WhatsApp Guides

WhatsApp Interactive Message Templates: Dynamic Webhook Catalog Guide

David O'Connor
9 min read
Views 1
Featured image for WhatsApp Interactive Message Templates: Dynamic Webhook Catalog Guide

Dynamic Logic in WhatsApp Interactive Message Templates

Static messaging kills conversion rates in SaaS and e-commerce. When a customer asks for a product list, sending an outdated PDF or a hard-coded text block creates friction. WhatsApp interactive message templates solve this by providing structured buttons and lists. However, the true value lies in dynamic lookups.

Dynamic lookup architecture ensures that the message a user sees reflects your current database state. If an item sells out in your warehouse, it must vanish from the WhatsApp interface within milliseconds. This requires a robust webhook listener and a middleware layer that translates database queries into compliant JSON payloads for the WhatsApp Business API or third-party providers like WASender.

Interactive templates include List Messages and Reply Buttons. List messages allow users to choose from up to ten options in a menu. Reply buttons provide up to three quick actions. Both require a backend that processes the user selection and returns a relevant response based on the specific ID associated with that interaction.

The Problem with Static Content

Static templates require manual updates through the Meta Business Suite or API configuration. This approach fails for businesses with more than five products or frequently changing prices. If you hard-code your catalog into a template, you face several risks.

First, you risk selling items that are out of stock. Second, you lose the ability to personalize recommendations based on the user's previous purchase history. Third, manual updates introduce human error. A typo in a price field leads to customer disputes and lost revenue.

Moving the logic to a dynamic webhook allows your server to act as the single source of truth. The WhatsApp message becomes a presentation layer while your database remains the engine. This separation of concerns simplifies maintenance and scales with your business growth.

Technical Prerequisites for Dynamic Lookups

Building this system requires a specific technical stack. You need a functioning WhatsApp API integration. This is achievable through the official Meta Cloud API or an unofficial session-based service like WASender for faster deployment.

Your infrastructure must include:

  1. A server capable of receiving POST requests (Node.js, Python, or Go are standard choices).
  2. A database containing your product catalog with unique identifiers (SKUs or UUIDs).
  3. An SSL-enabled endpoint to handle incoming webhooks securely.
  4. A messaging client to send the generated interactive responses back to the user.

Latency is a critical metric here. WhatsApp users expect near-instant responses. Aim for a webhook processing time under 200ms. If your database query takes longer, implement a caching layer like Redis to store your catalog metadata.

Implementing the Webhook Logic

The implementation starts when a user triggers an event. This event is often a keyword like "products" or a selection from a previous menu. Your webhook listener receives a JSON payload containing the sender's phone number and the message content.

Here is a standard structure for a Node.js webhook listener that handles incoming product requests:

const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

app.post('/whatsapp-webhook', async (req, res) => {
  const message = req.body.messages[0];
  const sender = message.from;

  if (message.type === 'text' && message.text.body.toLowerCase() === 'catalog') {
    const products = await getAvailableProductsFromDB();
    const interactivePayload = formatCatalogMessage(sender, products);
    await sendToWhatsApp(interactivePayload);
  }

  if (message.type === 'interactive') {
    const selectionId = message.interactive.list_reply.id;
    const details = await getProductDetails(selectionId);
    await sendToWhatsApp(formatDetailsMessage(sender, details));
  }

  res.status(200).send('EVENT_RECEIVED');
});

async function getAvailableProductsFromDB() {
  // Query your SQL or NoSQL database here
  // Return only items with stock > 0
  return [
    { id: 'SKU-100', name: 'Cloud Storage Pro', price: '$19' },
    { id: 'SKU-200', name: 'API Credits 10k', price: '$49' }
  ];
}

Constructing the Interactive Message JSON

The message you send back must follow a strict schema. For a product catalog, a list type message is the most effective. It organizes options into sections and provides a clear call to action.

Each row in the list needs a unique id. This id is the key for your dynamic lookup. When the user clicks the row, your webhook receives this id, allowing you to fetch the correct data for the next step in the flow.

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "1234567890",
  "type": "interactive",
  "interactive": {
    "type": "list",
    "header": {
      "type": "text",
      "text": "Our Current Software Plans"
    },
    "body": {
      "text": "Select a plan to view features and pricing."
    },
    "footer": {
      "text": "Last updated: 5 minutes ago"
    },
    "action": {
      "button": "View Plans",
      "sections": [
        {
          "title": "Subscriptions",
          "rows": [
            {
              "id": "sub_monthly",
              "title": "Monthly Pro",
              "description": "$29 per month, cancel anytime"
            },
            {
              "id": "sub_annual",
              "title": "Annual Enterprise",
              "description": "$250 per year, priority support"
            }
          ]
        }
      ]
    }
  }
}

Managing State and Context

Dynamic lookups become complex when the conversation has multiple steps. If a user selects a product, then asks for a discount code, your server must remember which product they selected.

Use a session management layer to track this context. Redis is the standard choice for this task. Store the user's phone number as the key and a JSON object representing their current state as the value. Set a Time-To-Live (TTL) of 24 hours to match the WhatsApp conversation window.

When the webhook receives a response, check the state store first. This tells your logic if the incoming button click is part of a checkout flow or a general inquiry. Without state management, your bot will lose the thread of the conversation every time the user clicks a button.

Practical Example: Real-Time Inventory Check

Consider a SaaS provider selling API credits. The price fluctuates based on server demand. A user sends a message to check pricing.

  1. The server receives the webhook.
  2. The server queries the pricing engine and the user's current balance.
  3. The server generates a reply button template showing three credit packages.
  4. Each button contains an ID that includes the current price hash to prevent price spoofing.
  5. The user clicks a button.
  6. The server validates the price hash and initiates the payment process.

This workflow ensures the user always sees the most accurate data. It prevents the frustration of clicking a button only to be told the price has changed or the package is no longer available.

Edge Cases and Failure Modes

Distributed systems fail in predictable ways. Your implementation must handle these scenarios to maintain a professional user experience.

Empty Search Results: If a user searches for a product that does not exist, do not send an empty list message. WhatsApp will reject the payload and return an error. Instead, send a standard text message explaining that no items were found and provide an alternative option.

Database Latency: If your database query hangs, your webhook might timeout. Use a message queue like BullMQ or RabbitMQ. Acknowledge the webhook immediately with a 200 OK status. Process the query in the background and send the WhatsApp message once the data is ready.

Character Limits: WhatsApp interactive messages have strict character limits. Headers are limited to 60 characters. Body text allows 1024 characters. List row titles allow 24 characters. If your product names are longer, implement a truncation function to avoid payload rejection.

Troubleshooting Integration Errors

When your interactive messages fail to deliver, check the following points first.

Payload Validation: Use a JSON linter to verify your structure. A missing comma or a mismatched bracket in the action object causes the entire message to fail. Verify that the type field matches the content of the interactive object.

Recipient Format: Ensure the phone number includes the country code but omits plus signs or leading zeros. Different providers have different requirements for number formatting.

Session Limits: Official WhatsApp API accounts have a 24-hour window. If you attempt to send an interactive message outside this window without a pre-approved template, the message will fail. If you use WASender, ensure your session is active and the QR code connection is stable.

Webhook Security: If your server ignores requests, check your SSL certificate. WhatsApp requires a valid, non-expired certificate from a trusted authority. Self-signed certificates will not work for official integrations.

FAQ

How many buttons can I include in an interactive message?

Reply button templates allow a maximum of three buttons. List messages allow one main button that opens a menu with up to ten rows across multiple sections. If you need more options, use a list message or chain multiple messages together.

Does this work with the WASender API?

Yes. WASender supports interactive messages. You send the JSON payload to the relevant endpoint. The dynamic lookup logic remains the same. You still need a backend to process the incoming webhooks and fetch your catalog data. This is often a faster way for developers to test interactive flows without waiting for Meta's template approval process.

Can I include images in interactive lists?

List messages do not support images in the individual rows. You can include an image in the header of the interactive message. If you need to show product images, send a multi-product message or a standard media message followed by a list message for selection.

What happens if the user types a response instead of clicking a button?

Your webhook logic should handle both cases. If the user types a message, your NLP or keyword matcher should attempt to guide them back to the structured flow. Always provide a way for the user to return to the main menu if they get stuck.

How do I handle multiple languages in dynamic catalogs?

Store translations in your database. When the webhook arrives, identify the user's language preference. Fetch the product titles and descriptions in that specific language. Construct the interactive JSON using these translated strings. This keeps your bot accessible to a global audience without creating separate templates for every language.

Next Steps for Implementation

Start by mapping your product categories to a list message structure. Determine which pieces of data need to be live. Build a simple webhook listener that returns a static list message first. Once the connectivity is verified, replace the static rows with a database query.

Monitor your webhook logs for errors. Pay close attention to the delivery status updates provided by the API. High failure rates often indicate issues with character limits or malformed IDs. Transitioning to dynamic lookups requires more initial engineering but reduces the long-term operational burden of managing your WhatsApp presence.

Share this guide

Share it on social media or copy the article URL to send it anywhere.

Use the share buttons or copy the article URL. Link copied to clipboard. Could not copy the link. Please try again.