Send Message

POST /api/external/send-message

Auth: Authorization: Bearer ck_<api_key> (required)

Send WhatsApp messages of type text, template, image, video, audio, or document.

Important: Do not use type: "text" with mediaUrl expecting a photo — that only delivers text. For photos/files use type: "image" (or video / audio / document) with mediaId or mediaUrl. Session media requires an open 24-hour customer window; outside that window use an approved template.

Request parameters

FieldRequiredTypeDescription
phoneNumberIdYesstringWhatsApp phone number ID to send from (must belong to your WABA)
toYesstringRecipient number with country code. Ten-digit Indian numbers are normalized to 91 prefix.
typeYesstringtext | template | image | video | audio | document
text / messageIf type=textstringMessage body. Either field name is accepted. For media types, may be used as caption if caption is omitted.
templateNameIf type=templatestringApproved template name in Meta
templateLanguageIf type=templatestringTemplate language code (e.g. en, en_US)
templateVariablesNoarray | objectBody variable values in order (array) or keyed by index
mediaIdFor session media*stringMeta media ID from Upload Media (preferred)
mediaUrlFor session media*stringPublic HTTPS link for session media, or template media header URL
captionNostringCaption for image / video / document (max 1024)
filenameNostringFilename for document type
buttonParametersNoarrayTemplate button components. Each item: type (url, quick_reply, phone_number, otp/copy_code, catalog), index, value
contextMessageIdNostringMeta message ID to reply in thread

* For image / video / audio / document, provide mediaId or mediaUrl.

Send image (session media)

Recommended: upload first, then send with mediaId.

curl -X POST https://chatyug.com/api/external/messages/upload-media \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -F "mediaFile=@photo.jpg" \
  -F "phoneNumberId=100000000000001" \
  -F "mediaType=image"

curl -X POST https://chatyug.com/api/external/send-message \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "100000000000001",
    "to": "919876543210",
    "type": "image",
    "mediaId": "900000000000099",
    "caption": "Product photo"
  }'

Send via public HTTPS link

{
  "phoneNumberId": "100000000000001",
  "to": "919876543210",
  "type": "image",
  "mediaUrl": "https://example.com/images/product.jpg",
  "caption": "Optional caption"
}

Document example

{
  "phoneNumberId": "100000000000001",
  "to": "919876543210",
  "type": "document",
  "mediaId": "900000000000099",
  "filename": "invoice.pdf",
  "caption": "Your invoice"
}

Response example

{
  "success": true,
  "message": "Message sent successfully",
  "requestId": "req_1720856400000_abc123def",
  "data": {
    "messageId": "wamid.HBgMOTE5ODc2NTQzMjEwFQIAERgSQjAwMDAwMDAwMDAwMDAwAA==",
    "conversationId": 1001,
    "status": "sent",
    "to": "919876543210",
    "type": "image",
    "timestamp": "2026-07-13T07:00:00.000Z"
  }
}

If the message was delivered to Meta but database save failed, warning may be present and delivery tracking may be limited.

Inbound media

Customer photos are stored under /received_media/.... Use GET /api/external/messages/:messageId/media for a stable ChatYug URL. Do not cache Meta lookaside.fbsbx.com links — they expire in minutes.

Code samples (template)

curl -X POST https://chatyug.com/api/external/send-message \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "100000000000001",
    "to": "919876543210",
    "type": "template",
    "templateName": "order_update",
    "templateLanguage": "en",
    "templateVariables": ["Rahul", "ORD-90001"]
  }'
const axios = require('axios');

await axios.post('https://chatyug.com/api/external/send-message', {
  phoneNumberId: '100000000000001',
  to: '919876543210',
  type: 'template',
  templateName: 'order_update',
  templateLanguage: 'en',
  templateVariables: ['Rahul', 'ORD-90001']
}, { headers: { Authorization: 'Bearer ck_your_api_key_here' } });
import requests

requests.post('https://chatyug.com/api/external/send-message', json={
    'phoneNumberId': '100000000000001',
    'to': '919876543210',
    'type': 'template',
    'templateName': 'order_update',
    'templateLanguage': 'en',
    'templateVariables': ['Rahul', 'ORD-90001']
}, headers={'Authorization': 'Bearer ck_your_api_key_here'})
$client = new GuzzleHttp\Client();
$client->post('https://chatyug.com/api/external/send-message', [
    'headers' => ['Authorization' => 'Bearer ck_your_api_key_here'],
    'json' => [
        'phoneNumberId' => '100000000000001',
        'to' => '919876543210',
        'type' => 'template',
        'templateName' => 'order_update',
        'templateLanguage' => 'en',
        'templateVariables' => ['Rahul', 'ORD-90001']
    ]
]);
Related webhook: After send, Meta pushes delivery updates to ChatYug, which forwards eventType: status to your webhook URL (delivered, read, failed).