Skip to main content
Send WhatsApp messages using POST /v2/messages/whatsapp. All message types use the same endpoint — the whatsapp_message object determines the message type.
POST https://api.telnyx.com/v2/messages/whatsapp

Request Structure

Every request requires these fields:
FieldTypeRequiredDescription
fromstringYesYour WhatsApp-enabled phone number (E.164)
tostringYesRecipient phone number (E.164)
whatsapp_messageobjectYesMessage content — structure varies by type
webhook_urlstringNoURL for delivery status callbacks
The messaging profile is automatically resolved from the from number. You do not need to pass messaging_profile_id.
The whatsapp_message object must include a type field and the corresponding content object. Supported types: text, template, image, video, document, audio, sticker, location, contacts, interactive, reaction.

Template Messages

Template messages are required to start conversations outside the 24-hour window. Templates must be pre-approved by Meta.
Error code 40008 indicates the template could not be used for sending. Possible causes include: the template is still pending review, was rejected by Meta, has been paused due to quality issues, or was disabled. Check template status in the Telnyx Portal or via GET /v2/whatsapp/message_templates.
Text, media, and interactive messages can only be sent within a 24-hour conversation window. The window opens when the recipient sends a message to the business number. Outside this window, use an approved template message to initiate the conversation.
For comprehensive template creation guidance, see the Message Template Best Practices guide.
curl -X POST https://api.telnyx.com/v2/messages/whatsapp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+15551234567",
    "to": "+15557654321",
    "whatsapp_message": {
      "type": "template",
      "template": {
        "name": "order_confirmation",
        "language": {
          "policy": "deterministic",
          "code": "en_US"
        },
        "components": [
          {
            "type": "body",
            "parameters": [
              {"type": "text", "text": "John"},
              {"type": "text", "text": "ORD-12345"}
            ]
          }
        ]
      }
    }
  }'

Template Components

Templates use components to pass dynamic content into header, body, and button slots:
Component typesub_typeUse
headerMedia or text for template header
bodyVariable substitution in body text
buttonquick_replyQuick reply button payload
buttonurlDynamic URL suffix for CTA buttons

Media Header Template

To send a template with an image header:
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "template",
    "template": {
      "name": "promo_with_image",
      "language": {"policy": "deterministic", "code": "en_US"},
      "components": [
        {
          "type": "header",
          "parameters": [
            {"type": "image", "image": {"link": "https://example.com/promo.jpg"}}
          ]
        },
        {
          "type": "body",
          "parameters": [
            {"type": "text", "text": "20%"}
          ]
        }
      ]
    }
  }
}
Header parameters also support document and video types with the same {link, caption, filename} structure.

Text Messages

Send plain text within the 24-hour conversation window. Body must be 1–4096 bytes.
curl -X POST https://api.telnyx.com/v2/messages/whatsapp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+15551234567",
    "to": "+15557654321",
    "whatsapp_message": {
      "type": "text",
      "text": {
        "body": "Thanks for reaching out! How can we help?",
        "preview_url": false
      }
    }
  }'
Set preview_url: true to render link previews when the message body contains a URL.

Media Messages

Send images, videos, documents, audio, and stickers. Each media object requires exactly one of link (URL) or id (Meta media ID). Captions are optional and limited to 1024 bytes.

Image

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "image",
    "image": {
      "link": "https://example.com/receipt.png",
      "caption": "Your receipt for order #12345"
    }
  }
}

Document

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "document",
    "document": {
      "link": "https://example.com/invoice.pdf",
      "filename": "invoice_12345.pdf",
      "caption": "Invoice for March 2026"
    }
  }
}

Video

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "video",
    "video": {
      "link": "https://example.com/tutorial.mp4",
      "caption": "Setup walkthrough"
    }
  }
}

Audio

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "audio",
    "audio": {
      "link": "https://example.com/voicenote.ogg"
    }
  }
}

Sticker

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "sticker",
    "sticker": {
      "link": "https://example.com/sticker.webp"
    }
  }
}
Stickers do not support captions. Audio does not support captions. Only one media type per message.

Location Messages

Share a location pin. Latitude and longitude are passed as strings (decimal format).
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "location",
    "location": {
      "latitude": "40.7128",
      "longitude": "-74.0060",
      "name": "Telnyx HQ",
      "address": "311 W 43rd St, New York, NY"
    }
  }
}
Latitude must be between -90 and 90. Longitude must be between -180 and 180.

Contact Messages

Share one or more contact cards (1–257 contacts per message).
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "contacts",
    "contacts": [
      {
        "name": {
          "formatted_name": "Jane Smith",
          "first_name": "Jane",
          "last_name": "Smith"
        },
        "phones": [
          {"phone": "+15559876543", "type": "WORK"}
        ],
        "emails": [
          {"email": "jane@example.com", "type": "WORK"}
        ]
      }
    ]
  }
}

Interactive Messages

Interactive messages let recipients tap buttons, select from lists, or open URLs. Supported interactive.type values:
TypeDescription
buttonUp to 3 quick reply buttons
cta_urlCall-to-action URL button
listSelectable list with sections and rows
location_request_messageRequest the recipient’s location
carouselScrollable cards with media and buttons

Quick Reply Buttons

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "interactive",
    "interactive": {
      "type": "button",
      "body": {"text": "Would you like to schedule a callback?"},
      "action": {
        "buttons": [
          {"type": "reply", "reply": {"id": "yes_callback", "title": "Yes, call me"}},
          {"type": "reply", "reply": {"id": "no_thanks", "title": "No thanks"}}
        ]
      }
    }
  }
}
When a recipient taps a button, you receive an inbound webhook with the button’s id in the payload.

CTA URL Button

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "interactive",
    "interactive": {
      "type": "cta_url",
      "body": {"text": "Track your shipment"},
      "action": {
        "name": "cta_url",
        "parameters": {
          "display_text": "Track Order",
          "url": "https://example.com/track/12345"
        }
      }
    }
  }
}

List Messages

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "interactive",
    "interactive": {
      "type": "list",
      "body": {"text": "Select a support topic:"},
      "action": {
        "button": "Choose topic",
        "sections": [
          {
            "title": "Account",
            "rows": [
              {"id": "billing", "title": "Billing", "description": "Payment and invoice questions"},
              {"id": "access", "title": "Account Access", "description": "Login and permissions"}
            ]
          },
          {
            "title": "Technical",
            "rows": [
              {"id": "api", "title": "API Issues", "description": "Integration and endpoint help"},
              {"id": "webhooks", "title": "Webhooks", "description": "Delivery and configuration"}
            ]
          }
        ]
      }
    }
  }
}

Location Request

{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "interactive",
    "interactive": {
      "type": "location_request_message",
      "body": {"text": "Share your location so we can find the nearest store."},
      "action": {"name": "send_location"}
    }
  }
}

Reactions

React to a received message with an emoji.
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "reaction",
    "reaction": {
      "message_id": "wamid.ABGGFlA5FpafAgo6tHcNmNjXhvRm",
      "emoji": "👍"
    }
  }
}

Reply Context

Reply to a specific message by including context.message_id:
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "text",
    "context": {
      "message_id": "wamid.ABGGFlA5FpafAgo6tHcNmNjXhvRm"
    },
    "text": {
      "body": "Thanks for your order! It will ship tomorrow."
    }
  }
}

Callback Tracking

Use biz_opaque_callback_data to attach tracking data that will be returned in delivery webhooks:
{
  "from": "+15551234567",
  "to": "+15557654321",
  "whatsapp_message": {
    "type": "text",
    "biz_opaque_callback_data": "order_12345_confirmation",
    "text": {
      "body": "Your order has been confirmed."
    }
  }
}

API Response

All message types return the same response structure:
{
  "data": {
    "record_type": "message",
    "direction": "outbound",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "type": "WHATSAPP",
    "from": {"phone_number": "+15551234567"},
    "to": [{"phone_number": "+15557654321", "status": "queued"}],
    "webhook_url": "https://example.com/webhooks"
  }
}

Validation Rules

ConstraintLimit
Text body1–4096 bytes
Media captionMax 1024 bytes
Header textMax 1024 bytes
Contacts per message1–257
Location latitude-90 to 90 (string)
Location longitude-180 to 180 (string)
Media per messageExactly 1
Media sourceExactly one of link or id

Error Handling

All WhatsApp-specific errors return error code 41000 (WhatsApp Error) with the underlying Meta API error in the response details. For general API errors, see the Error Codes Reference.
Template, text, media, and interactive messages all use the same endpoint. The type field inside whatsapp_message determines which content object is required.

Next Steps