Skip to main content

Send Message

Send a WhatsApp message to a customer — either an approved template (works any time) or a free-form message (only inside the 24-hour customer-service window).

Authentication Required

Requires the x-api-key header. See Overview for details.

HTTP Request

POST /api/dragonfly/whatsapp/messages

Request Body

FieldTypeRequiredDescription
recipientstringYesCustomer's WhatsApp number in international format — +<cc><number> or bare country-code-prefixed digits (e.g. 917545991999). Bare 10-digit national numbers are validated against your organisation's country.
typestringYesMessage type. template, text, image, video, audio, document, location, interactive, contacts, or reaction (case-insensitive).
templateNamestringFor templateName of the approved template.
languagestringFor templateTemplate language code. Must exactly match the template's language (enen_US) — copy it from List Templates.
componentsobject[]For templateTemplate variable values (header / body / button parameters), in Meta's components format. Pass [] for templates with no variables.
messageobjectFor non-template typesThe message payload, e.g. { "body": "hi" } for text.
contextobjectNoReply-to context ({ "message_id": "wamid..." }) to send as a threaded reply.

Examples

Free-form text message

Only works within 24 hours of the customer's last reply — see the 24-hour window.

{
"recipient": "917093245428",
"type": "text",
"message": { "body": "hi" }
}

Template with no variables

{
"recipient": "917545991999",
"type": "template",
"templateName": "hello_world",
"language": "en_US",
"components": []
}

Template with text variables in header & body

Body variables fill {{1}}, {{2}}, … in order; the header takes a single variable.

{
"recipient": "917545991999",
"type": "template",
"templateName": "waiting_request",
"language": "en",
"components": [
{ "type": "header", "parameters": [{ "type": "text", "text": "H1" }] },
{
"type": "body",
"parameters": [
{ "type": "text", "text": "B1" },
{ "type": "text", "text": "B2" }
]
}
]
}

Template with media in the header

Use parameter type image, video, or document with a public HTTPS link:

{
"recipient": "917545991999",
"type": "template",
"templateName": "video_in_header",
"language": "en",
"components": [
{
"type": "header",
"parameters": [
{ "type": "video", "video": { "link": "https://cdn.example.com/clip.mp4" } }
]
}
]
}

For a document: { "type": "document", "document": { "link": "https://…/file.pdf" } }. For an image: { "type": "image", "image": { "link": "https://…/pic.png" } }.

Template with a dynamic-URL button

The URL variable is supplied via a button component with sub_type: "url" and the button's index (0-based):

{
"recipient": "917545991999",
"type": "template",
"templateName": "dynamic_urll",
"language": "en",
"components": [
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [{ "type": "text", "text": "customer_first_name" }]
}
]
}
caution

Sending a dynamic-URL template with empty components fails — the button variable must always be provided.

Try it

Loading playground…

Code Examples

curl -X POST "https://prod-api.superfone.co.in/superfone/api/dragonfly/whatsapp/messages" \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"recipient": "917545991999",
"type": "template",
"templateName": "hello_world",
"language": "en_US",
"components": []
}'

Success Response

Status Code: 200 OK

{
"data": {
"messaging_product": "whatsapp",
"contacts": [
{ "input": "917545991999", "wa_id": "917545991999" }
],
"messages": [
{
"id": "wamid.HBgMOTE3NTQ1OTkxOTk5FQIAERgSMkMyM0I3NjU2QjdGRDYyN0NGAA==",
"message_status": "accepted"
}
]
},
"message": "success"
}

Save data.messages[0].id (the wamid) — you need it to look up delivery status.

"accepted" is not "delivered"

A 200 with a wamid means Meta accepted the message. Delivery, read, and failure happen asynchronously — check via Get Message by ID or a WhatsApp events webhook.

Insufficient balance

If your wallet balance cannot cover the send, the message is not sent but the API still returns HTTP 200 with this body instead of the Meta payload:

{
"message": "Insufficient wallet balance for sending message",
"reason": "INSUFFICIENT_BALANCE"
}
Check the body, not the status code

Never treat HTTP 200 alone as a successful send. A send succeeded only if data.messages[0].id is present.

Error Responses

StatusMessageWhen it occurs
400Template not foundtemplateName doesn't exist or language doesn't exactly match the template's language code
400Invalid Message Typetype is not one of the supported values
400Invalid RequestNo WhatsApp account is connected to your organisation
400(Meta error message)Meta rejected the send synchronously (bad recipient, template paused, etc.)
401UnAuthorized, Please Provide Valid API KeyMissing or invalid x-api-key