Interactive Service Messages

Interactive WhatsApp messages: CTA URL button, reply buttons, list, media carousel, and location request. Includes payload shapes and inbound-webhook formats for each type.

What Interactive Service Messages Are

Interactive service messages are non-template messages that include UI elements — buttons, lists, carousels, location-request prompts — beyond plain text or media. They are sent inside an open customer service window using the standard /messages endpoint with type: "interactive".

User responses (button taps, list selections, location shares) come back as inbound messages webhooks with the relevant action payload. In Dualhook setups, these webhooks go directly to your endpoint via Webhook Override — Dualhook does not ingest them.

The Interactive Wrapper

All interactive types share the same outer structure:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "<INTERACTIVE_TYPE>",
    "header": { /* optional, type-specific shape */ },
    "body":   { "text": "<BODY_TEXT>" },
    "footer": { "text": "<FOOTER_TEXT>" },
    "action": { /* required, type-specific shape */ }
  }
}

interactive.type selects which sub-type you're sending. The header, body, footer, and action fields each have type-specific shapes. Body is required for every type; header and footer are usually optional.

Type Overview

interactive.typeWhat it doesHeader?Footer?
cta_urlMap a URL to a buttonOptional (text/image/video/document)Optional
buttonUp to 3 reply buttonsOptional (text/image/video/document)Optional
listModal list with up to 10 sections × 10 rowsOptional (text only)Optional
carouselHorizontal scroll of 2–10 media cardsNot supportedNot supported
location_request_messageSend-location buttonNot supportedNot supported
address_messageIndia-only address form (see Address Messages)
flowWhatsApp Flows (see Meta's Flows docs)

CTA URL Button (cta_url)

Map a URL to a labeled button instead of dumping a raw URL into message text. Useful when the URL is long or obfuscated by tracking parameters.

{
  "messaging_product": "whatsapp",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "cta_url",
    "header": {
      "type": "image",
      "image": { "link": "https://example.com/banner.png" }
    },
    "body":   { "text": "Tap the button below to see available dates." },
    "footer": { "text": "Dates subject to change." },
    "action": {
      "name": "cta_url",
      "parameters": {
        "display_text": "See Dates",
        "url": "https://example.com?clickID=abc123"
      }
    }
  }
}
FieldLimitNotes
body.text1024 charsRequired. URLs auto-hyperlinked.
header.typetext, image, video, or document. Optional.
footer.text60 charsOptional. URLs auto-hyperlinked.
action.parameters.display_text20 charsRequired. Button label.
action.parameters.urlRequired. Loaded in default browser on tap.

Reply Buttons (button)

Up to 3 predefined reply buttons. Each tap triggers an inbound messages webhook with the button's id so your backend can route the user's choice.

{
  "messaging_product": "whatsapp",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "button",
    "header": { "type": "text", "text": "Choose an option" },
    "body":   { "text": "How can we help today?" },
    "footer": { "text": "Reply with one option." },
    "action": {
      "buttons": [
        { "type": "reply", "reply": { "id": "track_order",  "title": "Track order" } },
        { "type": "reply", "reply": { "id": "talk_to_agent","title": "Talk to agent" } },
        { "type": "reply", "reply": { "id": "stop_messages","title": "Stop messages" } }
      ]
    }
  }
}
FieldLimit
action.buttonsMax 3
reply.id256 chars
reply.title20 chars

List (list)

A list message displays a single button in the chat that, when tapped, opens a modal with up to 10 sections, each containing up to 10 rows. Total row count across all sections is capped at 10.

{
  "messaging_product": "whatsapp",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "list",
    "header": { "type": "text", "text": "Choose a category" },
    "body":   { "text": "Pick one and we'll send relevant updates." },
    "footer": { "text": "You can change preferences anytime." },
    "action": {
      "button": "Choose category",
      "sections": [
        {
          "title": "Notifications",
          "rows": [
            { "id": "orders",   "title": "Order updates",   "description": "Shipping, delivery, returns" },
            { "id": "billing",  "title": "Billing alerts",  "description": "Invoices and renewals" }
          ]
        },
        {
          "title": "Promotions",
          "rows": [
            { "id": "deals",    "title": "Deals",           "description": "Weekly offers" }
          ]
        }
      ]
    }
  }
}
FieldLimit
action.button20 chars (label on the modal-trigger button)
sectionsMax 10
rows (per section)Max 10
Total rows across all sectionsMax 10
row.title24 chars
row.description72 chars

Horizontally scrollable cards (2–10), each with an image or video header, optional body text, and either one URL button or one or more quick-reply buttons. Button shape and count must be identical across all cards.

{
  "messaging_product": "whatsapp",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "carousel",
    "body": { "text": "Here are three of our latest arrivals:" },
    "action": {
      "cards": [
        {
          "card_index": 0,
          "type": "cta_url",
          "header": { "type": "image", "image": { "link": "https://example.com/blue.jpg" } },
          "body":   { "text": "*Blue Echeveria*\n\nA rosette-shaped succulent." },
          "action": {
            "name": "cta_url",
            "parameters": { "display_text": "Buy now", "url": "https://shop.example.com/blue" }
          }
        },
        {
          "card_index": 1,
          "type": "cta_url",
          "header": { "type": "image", "image": { "link": "https://example.com/zebra.jpg" } },
          "body":   { "text": "*Zebra Haworthia*\n\nWhite stripes on green leaves." },
          "action": {
            "name": "cta_url",
            "parameters": { "display_text": "Buy now", "url": "https://shop.example.com/zebra" }
          }
        }
      ]
    }
  }
}

For quick-reply variants, use action.buttons (array of quick_reply objects with id + title) on each card instead of action.parameters.

FieldLimit
interactive.body.text1024 chars (required)
cardsMin 2, max 10
card.body.text160 chars, up to 2 line breaks (optional)
card.header.typeimage or video only
URL button display_text20 chars
Quick-reply title20 chars
Quick-reply id256 chars

Headers, footers, and other interactive components are not supported on the carousel wrapper itself — only on individual cards. All cards must use the same button shape.

Location Request (location_request_message)

Display body text plus a "send location" button. When the user taps it, WhatsApp opens the location-sharing screen.

{
  "messaging_product": "whatsapp",
  "to": "12015550123",
  "type": "interactive",
  "interactive": {
    "type": "location_request_message",
    "body": {
      "text": "Let's start with your pickup. *Enter an address* or *share your current location*."
    },
    "action": { "name": "send_location" }
  }
}

When the user shares their location, you receive a messages webhook with type: "location":

{
  "messages": [
    {
      "context": {
        "from": "15550001234",
        "id": "wamid.HBgL..."
      },
      "from": "12015550123",
      "id": "wamid.HBgL...",
      "timestamp": "1702920965",
      "location": {
        "latitude": 40.782910059774,
        "longitude": -73.959075808525,
        "name": "Solomon R. Guggenheim Museum",
        "address": "1071 5th Ave, New York, NY 10128"
      },
      "type": "location"
    }
  ]
}

name and address only appear if the user chose to share them. latitude/longitude are always present when the user shares.

Responses and Webhooks

The /messages API response shape is the same as for any service message: a messages array with the WhatsApp message ID. Acceptance does not confirm delivery — see Messaging Overview → Delivery Status Lifecycle.

User actions on interactive messages (button taps, list selections, location shares) arrive as inbound messages webhooks. Common shapes:

User actionInbound webhook typeKey fields
Tap a button replyinteractive.button_replyinteractive.button_reply.id, interactive.button_reply.title
Pick a list rowinteractive.list_replyinteractive.list_reply.id, interactive.list_reply.title, interactive.list_reply.description
Tap a carousel quick-replyinteractive.button_replyas above (per card)
Tap a CTA URL buttonNo inbound webhook for the tap itself (the URL opens externally)
Share locationlocationlatitude, longitude, optional name/address

For Dualhook customers these webhooks bypass our app entirely — they go straight to your endpoint via Webhook Override. See Messaging Webhook for full envelope and signature details.

Related

  • Service MessagesFree-form messages sent inside an open customer service window: type list, contextual replies, media caching, TTL, message quality, and pricing.
  • Address Messages (India)India-only interactive form for collecting structured shipping addresses inside WhatsApp. Covers prefill, saved addresses, validation errors, the nfm_reply submission webhook, and feature-not-supported (error 1026) fallback.
  • Messaging WebhookReal-time webhook events for inbound messages, delivery statuses, and errors.
  • WhatsApp Webhook OverrideHow Dualhook uses WhatsApp Webhook Override to route supported customer-path webhooks directly from Meta to your server.
Browse more docsStart Free Trial