Skip to main content

Send WABA Message

Agent Skill

Automate this endpoint with an AI agent using the 2chat-whatsapp-waba skill:

npx skills add 2ChatCo/agent-skills -s 2chat-whatsapp-waba

Send a message via WhatsApp Business API (WABA). You can send either a template message (for starting a conversation or after the 24-hour window) or a session message (plain text within an active conversation).

info

Requires a WABA channel connected to your 2Chat account. Get template UUIDs from the Get WABA Templates endpoint.

Request body (common fields)

FieldDescriptionRequired
to_numberRecipient number in E.164 format (e.g. +595981048477).Yes
from_numberYour WABA number in E.164 format (e.g. +5215512345432).Yes

For template messages, also send:

FieldDescriptionRequired
template_uuidTemplate UUID from Get WABA Templates.Yes
paramsTemplate variable values. Required for template messages; use an empty object {} (or e.g. {"body": []}) if the template has no variables.Yes
params.bodyArray of strings replacing {{1}}, {{2}}, … in the template body.If template has body variables
params.headerArray of strings replacing {{1}}, {{2}}, … in a TEXT header. Only for templates whose header is TEXT with placeholders.If applicable
params.header_media_urlPublic URL to the image, video, or document for templates with an IMAGE / VIDEO / DOCUMENT header. Must be http or https and publicly downloadable. 2Chat fetches the file and re-hosts it on its own storage before forwarding to WhatsApp, so short-lived signed URLs are fine as long as they are reachable at send time.If template has a media header
params.header_media_filenameOptional filename hint for DOCUMENT templates (e.g. invoice.pdf).No

For session messages (within 24-hour window), send:

FieldDescriptionRequired
textPlain text message.Yes
caution

You must send either a template message (template_uuid and params; params is required even if empty) or a session message (text), not both in the same request.


Send a template message

Use when starting a conversation or when the 24-hour session has expired. Replace template placeholders with values in params.body (and optionally params.header or params.buttons).

curl --request POST \
--url 'https://api.p.2chat.io/open/waba/send-message' \
--header 'Content-Type: application/json' \
--header 'X-User-API-Key: your_api_key_here' \
--data '{
"to_number": "+595981048477",
"from_number": "+5215512345432",
"template_uuid": "TMP1b44a079-c75c-4403-bc8f-a75c4ce5cd23",
"params": {
"body": ["Maria", "TRK-98452"]
}
}'

Send a template with a media header

Use this shape when the template's header is IMAGE, VIDEO, or DOCUMENT. Pass the public URL of the media in params.header_media_url. The type (image / video / document) is derived from the template — you do not need to specify it.

curl --request POST \
--url 'https://api.p.2chat.io/open/waba/send-message' \
--header 'Content-Type: application/json' \
--header 'X-User-API-Key: your_api_key_here' \
--data '{
"to_number": "+595981048477",
"from_number": "+5215512345432",
"template_uuid": "TMP1b44a079-c75c-4403-bc8f-a75c4ce5cd23",
"params": {
"body": ["Maria"],
"header_media_url": "https://example.com/promo.png"
}
}'

For DOCUMENT templates, you can also pass params.header_media_filename to control the filename shown to the recipient (e.g. "header_media_filename": "invoice.pdf"). For VIDEO templates, the request shape is identical to IMAGE — only params.header_media_url is needed.

Notes on media URLs
  • The URL must use http or https and resolve to a publicly reachable host. URLs pointing to private ranges (loopback, link-local, RFC1918) are rejected.
  • 2Chat downloads the file and re-hosts it on its own storage before sending to WhatsApp, so hot-link-protected CDNs work as long as the file can be fetched server-side.
  • The same hosted asset is reused across sends, so passing identical URLs is cheap.

Send a session message

Use when replying within the 24-hour customer session. Send only text (no template_uuid or params).

curl --request POST \
--url 'https://api.p.2chat.io/open/waba/send-message' \
--header 'Content-Type: application/json' \
--header 'X-User-API-Key: your_api_key_here' \
--data '{
"to_number": "+595981048477",
"from_number": "+5215512345432",
"text": "Hi, how can we help you today?"
}'

Response

Example success response:

{
"success": true,
"batched": true,
"message_uuid": "MSG126d9055-9dad-415f-b934-ff909773a8ef"
}
FieldDescription
successtrue when the message was accepted
batchedtrue when the message was successfully queued for sending
message_uuidInternal UUID of the message for tracking

Error responses

Errors return an HTTP 4xx status and a JSON body in the shape:

{
"error": true,
"error_message": "Template '...' has a IMAGE header. You must pass 'header_media_url' with a public URL to the media."
}

Common cases:

Statuserror_messageWhen
400from_number is requiredMissing required field
400to_number is requiredMissing required field
400template_uuid or text is requiredNeither is present
400template_uuid and text cannot be used togetherBoth are present
400`params` must be an objectparams is not a JSON object
400`params.header_media_url` must be a valid public URLURL has wrong type or invalid syntax
400Template '...' has a IMAGE header. You must pass 'header_media_url' ...Template expects media, caller did not pass header_media_url
400Template '...' has no media header. Do not pass 'header_media_url'.Template is TEXT-only and caller included header_media_url
400Could not fetch the media URL provided in 'params.header_media_url' ...URL unreachable, blocked by the SSRF guard (private/loopback host), or rejected by the scheme allowlist
400from_number does not exist on your accountNumber not found or marked for deletion
400Your WABA number (...) is not connected to 2ChatChannel is in a non-connected state