Skip to main content

WhatsApp Formatter

Transform LLM output to WhatsApp Business API JSON format.

This library uses an LLM to parse free-form text (with options, headers, footers) and automatically converts it to valid WhatsApp message formats (plain text, quick reply buttons, or interactive lists).

Installation

pip install whatsapp-formatter

Quick Start

import os
from whatsapp_formatter import format_for_whatsapp

# Configure LLM (works with any OpenAI-compatible API)
os.environ["LLM_API_KEY"] = "your-api-key"
os.environ["LLM_BASE_URL"] = "https://openrouter.ai/api/v1"  # Optional
os.environ["LLM_MODEL"] = "qwen/qwen3-30b-a3b-instruct-2507"  # Optional

# Format LLM output for WhatsApp
raw_text = """
I can help with your account. What would you like to do?

1. Check your balance
2. Transfer funds
3. View recent transactions
"""

result = format_for_whatsapp(raw_text)
print(result.whatsapp_json)

Output:

{
  "type": "interactive",
  "interactive": {
    "type": "button",
    "body": { "text": "I can help with your account. What would you like to do?" },
    "action": {
      "buttons": [
        { "type": "reply", "reply": { "id": "check_your_balance", "title": "Check your balance" } },
        { "type": "reply", "reply": { "id": "transfer_funds", "title": "Transfer funds" } },
        { "type": "reply", "reply": { "id": "view_recent_transac", "title": "View Transactions" } }
      ]
    }
  }
}

Features

  • Automatic format selection based on option count:

    • 0 options → Plain text message
    • 1-3 options → Quick reply buttons
    • 4-10 options → Interactive list
    • 11+ options → Plain text fallback with numbered list
  • Smart truncation to fit WhatsApp constraints:

    • Button titles: max 20 characters
    • List row titles: max 24 characters
    • Body text: max 1024 characters (interactive) or 1600 (plain text)
  • Automatic deduplication of option titles with suffixes

  • Header/footer extraction from structured messages

  • Multiple option formats supported:

    • Numbered lists (1. Option)
    • Bullet points (- Option, • Option)
    • Inline choices (Yes, No, or Cancel)

API Reference

format_for_whatsapp(text: str) -> TransformResult

The main entry point. Parses text and returns WhatsApp-ready JSON.

from whatsapp_formatter import format_for_whatsapp

result = format_for_whatsapp("Your balance is $500.")
print(result.format_used)      # FormatType.PLAIN_TEXT
print(result.whatsapp_json)    # {"type": "text", "text": {"body": "..."}}
print(result.fallback_used)    # False
print(result.modifications)    # List of any truncations applied

transform(llm_output: LLMOutput) -> TransformResult

Transform pre-parsed data to WhatsApp format (skip LLM parsing step).

from whatsapp_formatter import transform, LLMOutput, Option

llm_output = LLMOutput(
    body="Choose an option:",
    options=[
        Option(title="Yes"),
        Option(title="No"),
    ]
)
result = transform(llm_output)

parse(text: str) -> LLMOutput

Parse text using LLM (requires API key).

from whatsapp_formatter import parse

llm_output = parse("Select: 1. Apple 2. Banana 3. Cherry")
print(llm_output.body)     # "Select:"
print(llm_output.options)  # [Option(title="Apple"), ...]

Data Types

LLMOutput

class LLMOutput:
    body: str                    # Main message text (required)
    options: list[Option] | None # Flat list of options
    sections: list[Section] | None # Grouped options (for list format)
    header: str | None           # Optional header text
    footer: str | None           # Optional footer text

TransformResult

class TransformResult:
    success: bool                # Always True unless error
    whatsapp_json: dict          # Ready-to-send WhatsApp payload
    format_used: FormatType      # PLAIN_TEXT, QUICK_REPLY, or LIST
    fallback_used: bool          # True if format was downgraded
    fallback_reason: str | None  # Reason for fallback
    modifications: list[str]     # Truncations/deduplications applied

FormatType

class FormatType(Enum):
    PLAIN_TEXT = "plain_text"
    QUICK_REPLY = "quick_reply"
    LIST = "list"

Configuration

Environment Variables

Variable Description Default
LLM_API_KEY API key Required
LLM_BASE_URL API endpoint https://api.openai.com/v1
LLM_MODEL Model name gpt-4o-mini

Supported Providers

Works with any OpenAI-compatible API:

# OpenAI (default)
export LLM_API_KEY="sk-..."
export LLM_MODEL="gpt-4o-mini"

# OpenRouter
export LLM_API_KEY="sk-or-..."
export LLM_BASE_URL="https://openrouter.ai/api/v1"
export LLM_MODEL="qwen/qwen3-30b-a3b-instruct-2507"

# vLLM (self-hosted)
export LLM_API_KEY="token"
export LLM_BASE_URL="http://localhost:8000/v1"
export LLM_MODEL="meta-llama/Llama-3-8b-instruct"

# Ollama
export LLM_API_KEY="ollama"
export LLM_BASE_URL="http://localhost:11434/v1"
export LLM_MODEL="llama3"

# Together AI
export LLM_API_KEY="..."
export LLM_BASE_URL="https://api.together.xyz/v1"
export LLM_MODEL="meta-llama/Llama-3-70b-chat-hf"

# Groq
export LLM_API_KEY="..."
export LLM_BASE_URL="https://api.groq.com/openai/v1"
export LLM_MODEL="llama3-70b-8192"

Recommended Models

For best results with structured JSON extraction:

  • qwen/qwen3-30b-a3b-instruct-2507 (91%+ accuracy)
  • gpt-4o-mini (with JSON mode)

WhatsApp Constraints

The library automatically handles these WhatsApp Business API limits:

Element Max Length
Quick reply button title 20 chars
Quick reply buttons 3 max
List row title 24 chars
List row description 72 chars
List sections 10 max
List rows total 10 max
Interactive body 1024 chars
Plain text body 1600 chars
Header 60 chars
Footer 60 chars

Examples

Plain Text (no options)

result = format_for_whatsapp("Your balance is $500.")
# → {"type": "text", "text": {"body": "Your balance is $500."}}

Quick Reply (1-3 options)

result = format_for_whatsapp("""
Was this transaction authorized?
1. Yes
2. No
""")
# → {"type": "interactive", "interactive": {"type": "button", ...}}

List (4-10 options)

result = format_for_whatsapp("""
Select a service:
1. Balance
2. Transfer
3. Cards
4. Loans
5. Support
""")
# → {"type": "interactive", "interactive": {"type": "list", ...}}

With Header and Footer

result = format_for_whatsapp("""
⚠️ Security Alert

We detected a login from a new device. Was this you?

1. Yes, it was me
2. No, secure my account

Reply within 24 hours.
""")
# Extracts header: "Security Alert"
# Extracts footer: "Reply within 24 hours."

Development

# Clone the repository
git clone https://github.com/dnivra26/whatsapp-formatter.git
cd whatsapp-formatter

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

License

MIT License

Release files for whatsapp-formatter 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for whatsapp-formatter 0.2.0
File Size Uploaded
whatsapp_formatter-0.2.0.tar.gz 12.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for whatsapp-formatter 0.2.0
File Interpreter ABI Platform
whatsapp_formatter-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.3 kB

Release files / whatsapp_formatter-0.2.0.tar.gz

Download URL whatsapp_formatter-0.2.0.tar.gz
Size 12.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9f917fba232907beee047122665e394efa72ca10877fd7c53b03554c997e8d17
BLAKE2b-256 checksum
How to use checksums
56157a744eff23956b9e7c1c828c98192ecd43cb3394d7aa5d4ebf1ca4bc09ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Release files / whatsapp_formatter-0.2.0-py3-none-any.whl

Download URL whatsapp_formatter-0.2.0-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
31c52d7cb154cafb5a7092d07e9d1467fbf71e19dbc4ef995367e46c768fd158
BLAKE2b-256 checksum
How to use checksums
9ac43ef26787f4904b65d5342028bd1a837019fb0712f58ad7906ff91e26955e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.7

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page