Send Message (Direct Send)
| Method | POST |
| Endpoint | /\<WHATSAPP_BUSINESS_PHONE_NUMBER_ID>/messages |
| RML Connect Endpoint | https://apis.rmlconnect.net/wba/v1/tsp/messages |
| Purpose | Send a business-initiated Utility message without a pre-created template. Templates are matched or auto-created behind the scenes. |
If the category field is omitted, the endpoint falls back to standard Cloud API free-form message behavior.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
| messaging_product | string | Yes | Always "whatsapp" |
| recipient_type | string | Yes | "individual" |
| to | string | Yes | Recipient's WhatsApp phone number |
| type | string | Yes | Message type, e.g. "text" or "interactive" |
| text.body | string | Conditional | Body text, required when type is "text" |
| category | string | Yes (to invoke Direct Send) | "utility". Absent = normal Cloud API send behavior |
| ttl_seconds | integer | No | Custom message time-to-live; Direct Send only (see TTL section) |
| direct_send_config.template_name | string | No | Caller-supplied name to control which template the message is attributed to |
Category field — accepted values
| Value | Meaning |
|---|---|
| utility | Business-initiated Utility message; billed at utility rates |
| service | Service message; dropped if the service window is not open (existing behavior) |
| (absent) | Falls back to existing Cloud API send behavior — Direct Send is not invoked |
Basic request example
POST /\<WHATSAPP_BUSINESS_PHONE_NUMBER_ID>/messages
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "<WHATSAPP_USER_PHONE_NUMBER>",
"type": "text",
"text": {
"body": "<BODY_TEXT>"
},
"category": "utility"
}Attributing a message to a named template
To control which template a message is attributed to (rather than relying on auto-matching), pass direct_send_config.template_name.
| Rule | Detail |
|---|---|
| Format | Lowercase alphanumeric characters and underscores only — ^[a-z0-9_]+$ |
| Max length | 512 characters |
| Uniqueness | Must be unique within the WABA. Colliding with a non-Direct-Send template returns error 132021 (async, via error webhook) |
| Fallback behavior | template_name sends do NOT fall back to onboarding templates. On template creation failure the message is retried up to 3 times, then fails with error 131000 |
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "<WHATSAPP_USER_PHONE_NUMBER>",
"type": "text",
"text": {
"body": "Hi Jane, your order #12345 has been shipped and is expected to arrive on March 20."
},
"category": "utility",
"direct_send_config": {
"template_name": "order_shipment_update"
}
}Configuring TTL (time-to-live)
TTL is only supported on Direct Send messages. Add ttl_seconds below category.
| Setting | Value |
|---|---|
| Default TTL | 30 days |
| Minimum customizable | 30 seconds |
| Maximum customizable | 43200 seconds (12 hours) |
POST /\<WHATSAPP_BUSINESS_PHONE_NUMBER_ID>/messages
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "<WHATSAPP_USER_PHONE_NUMBER>",
"type": "text",
"text": {
"body": "<BODY_TEXT>"
},
"category": "utility",
"ttl_seconds": 600
}Success response
{
"messaging_product": "whatsapp",
"contacts": [{
"input": "PHONE_NUMBER",
"wa_id": "WHATSAPP_ID"
}],
"messages": [{
"id": "wamid.ID"
}]
}Error responses
| Case | Response |
|---|---|
| Invalid category value | Sync error, code 100 — "Param category must be one of {AUTHENTICATION, SERVICE, UTILITY}" |
| TTL on a non-Direct-Send message | Sync error, code 100 — "Invalid parameter" |
| TTL > 43200 seconds | Sync error, code 100 — "The time to live value must be lower than or equal to 43200" |
| TTL < 30 seconds | Sync error, code 100 — "The time to live value must be higher than or equal to 30" |
| template_name collides with existing non-Direct-Send template | Async error webhook, code 132021 |
| template_name creation fails after 3 retries | Async error webhook, code 131000 — "Something went wrong" |
| Message matches a paused template | Async error webhook, code 132015 |
| WABA under category-misuse restriction | Sync error, code 139200 — "Direct Send Utility access is blocked" |
| WABA rate-limited for category misclassification | Error code 131064 — messaging limit reached for the current 24h window |
Supported message types
- Text messages — body text plus optional link preview. Note: preview_url is not currently supported; Direct Send does not render URL previews.
- Interactive Call-to-Action (CTA) URL button messages (not recommended) — maps a URL to a button. Header may be text, image, video, or document (image/video/document access restricted — request via partner manager).
- Interactive reply button messages — up to three predefined reply options; a selection triggers a messages webhook.
- Interactive mixed CTA + reply button messages (recommended) — up to 10 buttons total, max 2 CTA buttons, CTA buttons always ordered before reply buttons.
Message format limits
| Element | Limit |
|---|---|
| Body text | 1024 characters |
| Header | 60 characters |
| Footer | 60 characters |
| Button text | 20 characters |
| Quick reply buttons | 10 max |
| CTA buttons | 2 max |
Message throughput follows standard Cloud API throughput eligibility rules.
Message status webhook — new field
The message status webhook payload gains a template_id field (under statuses) identifying the template used for a Direct Send message. Pricing and delivery status fields are otherwise at parity with the existing Cloud API status webhook.
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "<ID>",
"changes": [
{
"value": {
"messaging_product": "whatsapp",
"statuses": [
{
"id": "<ID>",
"status": "<read/delivered/sent>",
"timestamp": "<EPOCH_TIME>",
"recipient_id": "<RECIPIENT_PHONE_NUMBER>",
"template_id": "<TEMPLATE_ID>",
"conversation": { "..." : "..." },
"pricing": { "..." : "..." }
}
]
},
"field": "messages"
}
]
}
]
}Updated 17 days ago