Session Carousel API

1. Overview

Session Carousel lets a sender push a horizontally scrollable set of 2–10 cards (image/video header, body text, one CTA button per card) inside a single WhatsApp interactive message. RML accepts a simplified payload and converts it internally to the native WhatsApp Cloud API carousel interactive type before dispatch. This document covers the send-message payload, the internal conversion, the template-creation payload, and validation rules.

2. Send Message

Endpoint: POST https://apis.rmlconnect.net/wba-testing/v1/messages

2.1 RML Payload (input)

{
    "phone": "+9922892143",
    "media": {
        "type": "interactive_carousel",
        "body": "Check out our featured dishes for today",
        "cards": [
            {
                "header": {
                    "type": "image",
                    "url": "https://picsum.photos/200/300?grayscale"
                },
                "body": "Chicken Kadai - rich, spicy gravy",
                "buttons": [
                    { "type": "quick_reply", "text": "Order Kadai" }
                ]
            },
            {
                "header": {
                    "type": "image",
                    "url": "https://picsum.photos/200/300?grayscale"
                },
                "body": "Fish Masala - coastal flavour",
                "buttons": [
                    { "type": "quick_reply", "text": "Order Fish" }
                ]
            }
        ]
    }
}

2.2 Field Reference

FieldTypeRequiredConstraints
phonestringYesE.164-style; leading + optional (both formats seen across examples)
media.typestringYesMust be interactive _carousel
media.bodystringYesMax 1024 chars (SC-N9)
media.cardsarrayYes2–10 card objects (SC-N1, SC-N2)
cards[].headerobjectYesRequired per card (SC-N11)
cards[].header.typestringYesOne of image, video only (SC-N6)
cards[].header.urlstringYesMedia source URL
cards[].bodystringYesCard body text
cards[].buttonsarrayYesExactly 1 button per card (SC-N7, SC-N8)
buttons[].typestringYesquick_reply or url; same type across every card (SC-N3)
buttons[].textstringYesMax 25 chars (SC-N10)
buttons[].urlstringConditionalRequired if type=url (SC-N4); disallowed if type=quick_reply (SC-N5)

2.3 Converted Payload (WhatsApp Cloud API format, internal)

{
  "messaging_product": "whatsapp",
  "type": "interactive",
  "to": "+919922892143",
  "recipient_type": "individual",
  "interactive": {
    "type": "carousel",
    "body": { "text": "Check out our featured dishes for today" },
    "action": {
      "cards": [
        {
          "card_index": 0,
          "type": "button",
          "header": {
            "type": "image",
            "image": { "link": "https://.../sample01.jpg" }
          },
          "body": { "text": "Chicken Kadai - rich, spicy gravy" },
          "action": {
            "buttons": [
              {
                "type": "quick_reply",
                "quick_reply": { "id": "btn_0_0", "title": "Order Kadai" }
              }
            ]
          }
        },
        {
          "card_index": 1,
          "type": "button",
          "header": {
            "type": "image",
            "image": { "link": "https://.../sample02.jpg" }
          },
          "body": { "text": "Fish Masala - coastal flavour" },
          "action": {
            "buttons": [
              {
                "type": "quick_reply",
                "quick_reply": { "id": "btn_1_0", "title": "Order Fish" }
              }
            ]
          }
        }
      ]
    }
  }
}

Mapping Notes

  • phone → to, normalized to include country code (e.g. +9922892143 → +919922892143).
  • media.cards[] → interactive.action.cards[], each assigned a zero-indexed card_index.
  • header.url on input is not passed through verbatim to output in the reference sample; output uses image.link. Confirm whether this is a real re-hosting/CDN step or a documentation artifact (see Open Questions).
  • buttons[].id is synthesized as btn_{card_index}_{button_index} since RML input has no button ID field.

3. Template Creation

Purpose: register a reusable carousel template (as opposed to a one-off session send).

3.1 RML Payload

{
  "name": "session carousel",
  "type": "carousel",
  "templateDetails": {
    "bot_name": [ { "routeotp": "JIO" } ],
    "variables": ["test1", "test2", "rml_ctr_postback"],
    "category": "carousel",
    "payload": {}
  },
  "width": "SMALL_WIDTH",
  "height": "SHORT_HEIGHT",
  "carouselList": [
    {
      "suggestions": [
        {
          "displayText": "hello card1[test1]",
          "suggestionType": "reply",
          "postback": "[rml_ctr_postback]::text"
        }
      ],
      "cardTitle": "card1[test1]",
      "cardDescription": "card1[test1]",
      "mediaUrl": "https://fastly.picsum.photos/id/1071/200/200.jpg"
    },
    {
      "suggestions": [
        {
          "displayText": "hello card2[test2]",
          "suggestionType": "reply",
          "postback": "[rml_ctr_postback]::text"
        }
      ],
      "cardTitle": "card2[test2]",
      "cardDescription": "card2[test1]",
      "mediaUrl": "https://fastly.picsum.photos/id/1071/200/200.jpg"
    }
  ]
}

3.2 Field Reference

FieldTypeNotes
namestringTemplate name
typestringcarousel
templateDetails.bot_namearrayBot/channel binding, keyed by carrier (e.g. routeotp: JIO)
templateDetails.variablesarrayNamed placeholders referenced in card text via [variable] syntax; includes reserved rml_ctr_postback
width / heightstringCard sizing; observed values SMALL_WIDTH / SHORT_HEIGHT — full enum not confirmed
carouselList[].suggestionsarrayPer-card CTA(s); suggestionType: reply maps to quick-reply behavior
carouselList[].postbackstringFormat [variable]::text — payload contract not fully specified
carouselList[].cardTitle / cardDescriptionstringSupport inline variable substitution, e.g. card1[test1]
carouselList[].mediaUrlstringHeader media source

4. Validation Rules (Send API)

All violations return HTTP 422.

RuleTriggerReference
Card countMust be 2–10 cardsSC-N1, SC-N2
Uniform button typeAll cards must use the same button-type combinationSC-N3
URL button completenessurl required when type = urlSC-N4
Quick-reply button purityurl not allowed when type = quick_replySC-N5
Header typeMust be image or videoSC-N6
Buttons per card (min)At least 1 button requiredSC-N7
Buttons per card (max)Exactly 1 button allowedSC-N8
Carousel body lengthMax 1024 charsSC-N9
Button text lengthMax 25 charsSC-N10
Header presenceRequired on every cardSC-N11

5. Test Cases

IDScenarioExpected
SC-N1Single card (below minimum)422 — carousel must contain 2–10 cards
SC-N211 cards (above maximum)422 — carousel must contain 2–10 cards
SC-N3Card 1 quick_reply, card 2 url422 — all cards must use the same button-type combination
SC-N4url button missing url field422 — url is required when button type is url
SC-N5quick_reply button with url field set422 — url is not allowed when button type is quick_reply
SC-N6Header type document422 — header type must be one of [image, video]
SC-N7Card with 0 buttons422 — buttons list length must be between 1 and 1
SC-N8Card with 2 buttons422 — buttons list length must be between 1 and 1
SC-N9Carousel body > 1024 chars422 — longer than maximum length 1024 (body)
SC-N10Button text > 25 chars422 — longer than maximum length 25 (button text)
SC-N11Card missing header422 — header is required for each carousel card
SC-N12All cards use url buttons, otherwise valid (happy path)200 — message queued/sent successfully

Did this page help you?