Documentation menu

Guides

Sending messages

Every send route shares one shape: clientId, to, its own fields, and an optional envelope for replies, mentions and attribution.

The send envelope

These three optional fields are accepted by every POST /send-* route:

FieldTypeEffect
quotedMessageIdstringSend as a reply to that message. WhatsApp renders the quote from its own copy; with the hosted inbox we also fill the preview.
mentionsstring[]User-parts (LID or phone digits) to @-mention. Put @<user-part> in the text so clients highlight it.
metaDataobjectAny JSON, travels with the message and comes back as meta on the fromMe webhook and in hosted history. {"fromAI": true} also flags the stored row.

to accepts a LID (123456789012345), a phone with + (+60123456789), or a full JID including groups (…@g.us). See LIDs vs phone numbers.

Text, replies, mentions

POST https://api.meowsapp.com/send-message
{
  "clientId": "acmemain",
  "to": "123456789012345",
  "body": "Hi @60111111111111 — the unit on level 12 is still available.",
  "quotedMessageId": "3EB0C4D5E6F7",
  "mentions": ["60111111111111"],
  "metaData": { "fromAI": true, "userId": "flow_sales_v2" }
}

Typing indicator

Show "typing…" before a reply for a natural feel, especially from bots. It clears itself when the message is sent.

POST https://api.meowsapp.com/send-typing   { "clientId": "acmemain", "to": "123456789012345", "composing": true }

Polls

POST https://api.meowsapp.com/send-poll-message
{ "clientId": "acmemain", "to": "123456789012345", "pollName": "Which slot suits you?", "pollOptions": ["Sat 3 pm", "Sun 11 am", "Neither"], "selectableCount": 1 }
// vote → webhook type "vote_update", pollVote: { "pollMessageId": "…", "selectedNames": ["Sat 3 pm"], "resolved": true }

Store the options you sent against the returned messageId, or configure a pollLookupUrl, so votes come back resolved to names — see poll votes.

Buttons

POST https://api.meowsapp.com/send-interactive-message
{
  "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" }
  ]
}
// tap → webhook type "interactive_reply", interactive: { "selectedId": "confirm", "selectedDisplayText": "Confirm" }
typeRequired fieldsBehaviour
quick_replydisplayText, idSends id back as an interactive_reply event.
cta_urldisplayText, urlOpens the link.
cta_calldisplayText, phoneNumberStarts a phone call.
cta_copydisplayText, id, copyCodeCopies copyCode to the clipboard.

Buttons render differently across WhatsApp versions

Some older clients show interactive messages as plain text. Design flows so a typed reply ("1", "confirm") works too.

Reactions & edits

POST https://api.meowsapp.com/send-reaction   { "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "emoji": "👍" }
POST https://api.meowsapp.com/send-reaction   { "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "emoji": "" }        // remove
POST https://api.meowsapp.com/edit-message    { "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "body": "Saturday, 4 pm" }

Edits work on your own text messages for roughly 15 minutes after sending (WhatsApp's rule). Previous text is kept in hosted history under extras.editHistory.

Locations & contact cards

POST https://api.meowsapp.com/send-location  { "clientId": "acmemain", "to": "123456789012345", "latitude": 3.1579, "longitude": 101.7116, "name": "Acme Gallery", "address": "Jalan Ampang, KL" }
POST https://api.meowsapp.com/send-contact   { "clientId": "acmemain", "to": "123456789012345", "displayName": "Acme Sales", "phone": "+60123456789" }

Deleting

POST https://api.meowsapp.com/delete-message
{ "clientId": "acmemain", "to": "123456789012345", "messageId": "3EB0…", "fromMe": true, "mode": "everyone" }

mode: "everyone" revokes for all participants (only your own messages — WhatsApp enforces it). mode: "me" removes it from this device and from hosted history.

Attributing sends (AI vs human)

When several systems share one number — an AI agent, a human inbox, a notification pipeline — put the origin in metaData. It is embedded in the message itself, so the fromMe webhook (and hosted history) can tell them apart with no joins:

"metaData": { "fromAI": true, "userId": "flow_sales_v2", "sender": "Acme Assistant", "campaign": "aug-launch" }

Responses & partial success

{ "status": "sent", "messageId": "3EB0A1B2C3D4E5F6" }
{ "status": "sent", "messageId": "3EB0…", "warning": "sent but failed to save to inbox: …" }   // delivered; only hosted history failed
StatusMeaningRetry?
200Delivered to WhatsApp.
400Missing/invalid fields.No — fix the request.
404Unknown or unpaired clientId.No — check /check-state, re-pair if needed.
502WhatsApp rejected it or the session is offline. Nothing was delivered.Yes, with backoff.