Documentation menu

API reference

Messages

Every send route takes `clientId` and `to`, accepts the optional envelope fields (`quotedMessageId`, `mentions`, `metaData`), and responds `{status: "sent", messageId}`. A `warning` field means the message was delivered but could not be written to hosted history.

POST/send-messageSend text
POST/send-media-messageSend media by URL
POST/send-media-messageSend media by upload
POST/send-poll-messageSend a poll
POST/send-interactive-messageSend buttons
POST/send-reactionReact to a message
POST/edit-messageEdit a sent message
POST/send-locationSend a location
POST/send-contactSend a contact card
POST/send-typingTyping indicator
POST/delete-messageDelete a message
POST/send-message

Send text

Plain text, optionally as a reply or with mentions.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
bodyrequiredstringMessage text.
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{
  "clientId": "acmemain",
  "to": "123456789012345",
  "body": "Hi @60111111111111, your order is ready.",
  "mentions": ["60111111111111"],
  "quotedMessageId": "3EB0…",
  "metaData": { "fromAI": false, "userId": "agent_7" }
}
Response · 200
{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/send-media-message

Send media by URL

JSON mode: we fetch the file from a public URL and send it as image, video, audio, document, voice note or sticker.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
downloadUrlrequiredstringPublic https URL. Fetched with a 60 s timeout; 100 MB cap.
mimeTypestringOverrides the type detected from the response headers / file name.
captionstringIgnored for audio (WhatsApp has no audio captions).
fileNamestringShown for documents.
sendAudioAsVoicebooleanSend audio as a voice note (push-to-talk bubble). Supply OGG/Opus.
asStickerbooleanSend a WebP as a sticker.
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{
  "clientId": "acmemain",
  "to": "123456789012345",
  "downloadUrl": "https://files.example.com/brochure.pdf",
  "fileName": "Brochure.pdf",
  "caption": "Here is the brochure"
}
Response · 200
{ "status": "sent", "messageId": "3EB0…", "mediaType": "document", "bytes": 482113 }
// files over 60 MB are delivered as a text message containing the link:
{ "status": "sent", "messageId": "3EB0…", "fallback": "text" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
502The URL could not be fetched (non-200, timeout, or over 100 MB).
POST/send-media-message

Send media by upload

Multipart mode: upload the bytes directly. The media kind is inferred from the part's Content-Type (image/*, video/*, audio/*, otherwise document).

Also pass clientId in the URL

For multipart requests the router cannot read the form body, so add ?clientId=… to the URL. JSON routes do not need this.

ParameterTypeDescription
filerequiredfileThe binary, with a correct Content-Type.
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
captionstring
sendAudioAsVoice"true"
asSticker"true"
quotedMessageIdstring
mentionsstringComma separated.
metaDatastringJSON string.
Request
curl -X POST "https://api.meowsapp.com/send-media-message?clientId=acmemain" \
  -H "Authorization: Bearer $SN_TOKEN" \
  -F "file=@photo.jpg;type=image/jpeg" \
  -F clientId=acmemain -F to=123456789012345 -F caption="Here you go"
Response · 200
{ "status": "sent", "messageId": "3EB0…", "mediaType": "image" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
  • Keep files ≤ 64 MB to stay within WhatsApp's own limits; the ingress accepts up to 128 MB.
POST/send-poll-message

Send a poll

Native WhatsApp poll. Votes come back as vote_update events.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
pollNamerequiredstringThe question.
pollOptionsrequiredstring[]2–12 options.
selectableCountnumberHow many options a voter may pick. Default 1.
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "pollName": "Lunch?", "pollOptions": ["Pizza", "Sushi"], "selectableCount": 1 }
Response · 200
{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/send-interactive-message

Send buttons

Native-flow buttons: quick replies, open-URL, call and copy-code. Taps come back as interactive_reply events.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
bodyTextrequiredstring
footerTextstring
buttonsrequiredButton[]{type, displayText, id?, url?, phoneNumber?, copyCode?} — see table below.
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{
  "clientId": "acmemain",
  "to": "123456789012345",
  "bodyText": "Confirm your viewing on Saturday 3 pm?",
  "footerText": "Acme Realty",
  "buttons": [
    { "type": "quick_reply", "displayText": "Confirm", "id": "confirm" },
    { "type": "quick_reply", "displayText": "Reschedule", "id": "reschedule" },
    { "type": "cta_url", "displayText": "Directions", "url": "https://maps.example.com/site" },
    { "type": "cta_call", "displayText": "Call agent", "phoneNumber": "+60123456789" },
    { "type": "cta_copy", "displayText": "Copy code", "id": "code", "copyCode": "VIEW-2026" }
  ]
}
Response · 200
{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
  • Button types — quick_reply: displayText, id · cta_url: displayText, url · cta_call: displayText, phoneNumber · cta_copy: displayText, id, copyCode.
  • Rendering of interactive messages depends on the recipient's WhatsApp version; keep a text fallback in your flow.
POST/send-reaction

React to a message

Add or remove an emoji reaction.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
messageIdrequiredstringTarget message id.
emojirequiredstring"" removes your reaction.
targetFromMebooleanSet true when reacting to your own message.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "emoji": "👍" }
Response · 200
{ "status": "sent", "messageId": "3EB0…(reaction)", "targetId": "3EB0…" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/edit-message

Edit a sent message

Edit one of your own text messages. WhatsApp allows edits for roughly 15 minutes after sending.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
messageIdrequiredstringYour message's id.
bodyrequiredstringNew text.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "body": "Corrected: Saturday 4 pm" }
Response · 200
{ "status": "sent", "messageId": "3EB0…(edit)", "targetId": "3EB0…" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/send-location

Send a location

A pinned location with optional label.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
latituderequirednumber
longituderequirednumber
namestring
addressstring
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "latitude": 3.1579, "longitude": 101.7116, "name": "Acme Gallery", "address": "Jalan Ampang, KL" }
Response · 200
{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/send-contact

Send a contact card

A tappable vCard. Supply phone and we build the card, or pass a full vcard.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
displayNamerequiredstring
phonestringE.164 digits.
vcardstringFull vCard 3.0 text (overrides phone).
quotedMessageIdstringReply to this message id. The preview is filled from hosted history when available; unknown ids still send.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Include @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON you want echoed back. Delivered on the fromMe webhook as meta and stored with the message. {"fromAI": true} also flags the row as AI-sent.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "displayName": "Acme Sales", "phone": "+60123456789" }
Response · 200
{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/send-typing

Typing indicator

Show or clear "typing…" in the recipient's chat. Send before a reply for a natural feel.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
composingbooleanDefault true; false clears.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "composing": true }
Response · 200
{ "status": "ok" }
StatusWhen
400Missing or invalid fields.
404Unknown or unpaired clientId.
502WhatsApp rejected the send — nothing was delivered. Retry with backoff; check /check-state if it persists.
POST/delete-message

Delete a message

Delete for everyone (your own messages only — WhatsApp enforces this) or remove from this device only.

ParameterTypeDescription
clientIdrequiredstringYour account identifier (letters and digits only).
torequiredstringRecipient: a LID user-part (123456789012345), a phone with + (+60123456789, resolved to the contact's LID when known), or a full JID (…@lid, …@s.whatsapp.net, groups …@g.us).
messageIdrequiredstring
fromMerequiredbooleanWhether the message was sent by this session.
moderequired"everyone" | "me"
chatRoomIdstringRequired for mode: "me" when using hosted history.
Request · JSON body
{ "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "fromMe": true, "mode": "everyone" }
Response · 200
{ "status": true }
StatusWhen
400Bad mode or missing fields.
404Unpaired session, or (mode: me) message not found in history.
502WhatsApp rejected the revoke.