send_message_with_list
Send WhatsApp messages with interactive selection lists to present options, gather responses, and organize information in structured sections.
Instructions
Send a message with a selection list.
CONSTRAINTS:
Maximum 10 sections per list
Maximum 10 rows total across all sections
Button text: max 20 characters
Section title: max 24 characters
Row title: max 24 characters
Row description: max 72 characters
Row ID (callback_data): max 200 characters
Header text: max 60 characters (if provided)
Footer text: max 60 characters (if provided)
EXAMPLE: { "to": "+1234567890", "text": "Choose from our menu:", "button_text": "View Menu", "sections": [ { "title": "Main Courses", "rows": [ {"id": "burger", "title": "Burger", "description": "Beef burger with fries"}, {"id": "pizza", "title": "Pizza", "description": "Margherita pizza"} ] }, { "title": "Beverages", "rows": [ {"id": "coke", "title": "Coca Cola", "description": "Cold refreshing drink"}, {"id": "water", "title": "Water", "description": "Still or sparkling"} ] } ], "header": "Restaurant Menu", "footer": "All items available today" }
Args:
to: Phone number (with country code) or WhatsApp ID
text: Message body text (main message content)
button_text: Text shown on the list button (triggers the list)
sections: List of sections, each with 'title' and 'rows' arrays
header: Optional header text (appears above main text)
footer: Optional footer text (appears below list button)
reply_to_message_id: Message ID to reply to
Returns: Dictionary with success status and message ID
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | ||
| text | Yes | ||
| button_text | Yes | ||
| sections | Yes | ||
| header | No | ||
| footer | No | ||
| reply_to_message_id | No |
Implementation Reference
- tools/interactive.py:104-244 (handler)The main implementation of send_message_with_list function that sends WhatsApp messages with interactive list sections. It includes comprehensive validation for all WhatsApp list constraints (max 10 sections, 10 rows total, character limits for titles, descriptions, etc.), constructs SectionList objects using PyWA library types, and sends the message via wa_client.send_message().
async def send_message_with_list( to: str, text: str, button_text: str, sections: List[Dict[str, Any]], header: Optional[str] = None, footer: Optional[str] = None, *, reply_to_message_id: Optional[str] = None, ) -> dict: """ Send a message with a selection list. CONSTRAINTS: - Maximum 10 sections per list - Maximum 10 rows total across all sections - Button text: max 20 characters - Section title: max 24 characters - Row title: max 24 characters - Row description: max 72 characters - Row ID (callback_data): max 200 characters - Header text: max 60 characters (if provided) - Footer text: max 60 characters (if provided) EXAMPLE: { "to": "+1234567890", "text": "Choose from our menu:", "button_text": "View Menu", "sections": [ { "title": "Main Courses", "rows": [ {"id": "burger", "title": "Burger", "description": "Beef burger with fries"}, {"id": "pizza", "title": "Pizza", "description": "Margherita pizza"} ] }, { "title": "Beverages", "rows": [ {"id": "coke", "title": "Coca Cola", "description": "Cold refreshing drink"}, {"id": "water", "title": "Water", "description": "Still or sparkling"} ] } ], "header": "Restaurant Menu", "footer": "All items available today" } Args: to: Phone number (with country code) or WhatsApp ID text: Message body text (main message content) button_text: Text shown on the list button (triggers the list) sections: List of sections, each with 'title' and 'rows' arrays header: Optional header text (appears above main text) footer: Optional footer text (appears below list button) reply_to_message_id: Message ID to reply to Returns: Dictionary with success status and message ID """ try: # Validate constraints if len(sections) > 10: return {"success": False, "error": "Maximum 10 sections allowed"} if len(button_text) > 20: return {"success": False, "error": "Button text must be max 20 characters"} if header and len(header) > 60: return {"success": False, "error": "Header text must be max 60 characters"} if footer and len(footer) > 60: return {"success": False, "error": "Footer text must be max 60 characters"} # Count total rows across all sections total_row_count = sum(len(section.get("rows", [])) for section in sections) if total_row_count > 10: return {"success": False, "error": "Maximum 10 rows total across all sections"} # Convert sections to PyWA Section objects section_objects = [] for section_data in sections: if "rows" not in section_data: return {"success": False, "error": "Each section must have a 'rows' array"} section_title = section_data.get("title", "") if len(section_title) > 24: return {"success": False, "error": f"Section title '{section_title}' exceeds 24 characters"} rows = [] for row_data in section_data["rows"]: # Validate required fields if "id" not in row_data or "title" not in row_data: return {"success": False, "error": "Each row must have 'id' and 'title' keys"} # Validate constraints if len(row_data["id"]) > 200: return {"success": False, "error": f"Row ID '{row_data['id']}' exceeds 200 characters"} if len(row_data["title"]) > 24: return {"success": False, "error": f"Row title '{row_data['title']}' exceeds 24 characters"} description = row_data.get("description", "") if len(description) > 72: return {"success": False, "error": f"Row description '{description}' exceeds 72 characters"} rows.append(SectionRow( title=row_data["title"], callback_data=row_data["id"], description=description if description else None )) if rows: # Only add section if it has rows section_objects.append(Section( title=section_title, rows=rows )) # Create SectionList section_list = SectionList( button_title=button_text, sections=section_objects ) result = wa_client.send_message( to=to, text=text, buttons=section_list, header=header, footer=footer, reply_to_message_id=reply_to_message_id, ) logger.info(f"Message with list sent to {to}") message_id = getattr(result, 'id', str(result)) if result else None return {"success": True, "message_id": message_id} except Exception as e: logger.error(f"Failed to send message with list: {str(e)}") return {"success": False, "error": str(e)} - tools/interactive.py:103-103 (registration)The @mcp.tool() decorator that registers the send_message_with_list function as an MCP tool, making it available for use through the Model Context Protocol.
@mcp.tool() - tools/interactive.py:11-12 (registration)The register_interactive_tools function that contains the send_message_with_list tool definition and registers it with the MCP server instance.
def register_interactive_tools(mcp, wa_client: WhatsApp): """Register interactive messaging tools.""" - tools/interactive.py:104-111 (schema)Function signature and type definitions for send_message_with_list, defining the input parameters including required fields (to, text, button_text, sections) and optional fields (header, footer, reply_to_message_id) with their types.
async def send_message_with_list( to: str, text: str, button_text: str, sections: List[Dict[str, Any]], header: Optional[str] = None, footer: Optional[str] = None, *, - tools/interactive.py:6-6 (helper)Import of PyWA types (SectionList, Section, SectionRow) used within the send_message_with_list function to construct the interactive list structure.
from pywa.types import Button, SectionList, Section, SectionRow