Documentation menu

API reference

Webhook events

Every event we POST to your webhookUrl. All share the envelope; each type adds at most one object.

Envelope

Headers: Content-Type: application/json, Authorization: Bearer <webhookToken>, User-Agent: Meowsapp-WhatsApp/1, X-SN-Event: <type>. Delivery rules are in the Receiving messages guide.

Event (all fields)
{
  "event": "message.received",
  "type": "text",
  "clientId": "acmemain",
  "orgId": "acme",
  "timestamp": "2026-08-28T05:22:55Z",

  "chatRoomId": "acmemain-60111111111111-123456789012345",
  "myLid": "60111111111111",
  "clientLid": "123456789012345",
  "remoteJid": "123456789012345@lid",
  "remoteName": "Jane Lim",
  "remotePhone": "60123456789",
  "remoteUsername": "janelim",
  "avatarUrl": "https://files.meowsapp.com/…/avatars/123456789012345/1965117713.jpg",
  "pushName": "Jane",
  "fromMe": false,
  "isGroup": false,

  "messageId": "3EB0A1B2C3D4E5F6",
  "body": "Hello there",

  "quoted":      { "messageId": "3EB0…", "participant": "6011…", "body": "Earlier text", "type": "text" },
  "mentions":    ["60111111111111"],
  "isForwarded": false,
  "meta":        { "fromAI": true, "userId": "u_42", "sender": "Ops bot", "raw": { "campaign": "aug" } },

  "media":       { "…": "type = image | video | audio | document | sticker" },
  "poll":        { "…": "type = poll_creation" },
  "pollVote":    { "…": "type = vote_update" },
  "interactive": { "…": "type = interactive_reply" },
  "contact":     { "…": "type = contact" },
  "location":    { "…": "type = location" },
  "reaction":    { "…": "type = reaction" },
  "edit":        { "…": "type = edit" },
  "revoke":      { "…": "type = revoke" },
  "group":       { "…": "only when isGroup = true" }
}
text

Text message

A plain text message. body holds the text.

  • Replies carry quoted; @-mentions carry mentions; forwarded messages set isForwarded: true.
imagevideoaudiodocumentsticker

Media message

A file was sent. The bytes are not included; media.download lets you fetch and decrypt it, or use the hosted inbox to have it stored for you.

event.media
{
  "mimeType": "image/jpeg",
  "mediaType": "image",
  "fileName": "photo.jpg",
  "fileSize": 102400,
  "caption": "Here you go",
  "download": {
    "directPath": "/v/t62.7118-24/…",
    "mediaKey": "base64…",
    "fileSha256": "base64…",
    "fileEncSha256": "base64…",
    "fileLength": 102400
  }
}
  • mediaKey decrypts the file — treat it as a secret.
  • Stickers are WebP with mediaType: "sticker". Voice notes arrive as audio with mimeType: "audio/ogg; codecs=opus".
  • See the Media guide for downloading, or point webhookUrl at the hosted inbox and read downloadUrl from history instead.
poll_creation

Poll created

Someone sent a poll.

event.poll
{ "name": "Lunch?", "options": ["Pizza", "Sushi"], "selectableCount": 1 }
  • Store options against messageId — you need them to resolve votes (or configure pollLookupUrl).
vote_update

Poll vote

Someone voted on a poll.

event.pollVote
{
  "pollMessageId": "3EB0…",
  "selectedNames": ["Pizza"],
  "selectedHashes": ["a1b2…"],
  "resolved": true
}
  • resolved: true with selectedNames when we could look up the poll (hosted inbox, or your pollLookupUrl).
  • Otherwise resolved: false and selectedHashes = hex SHA-256 of each chosen option name; match against your stored options.
interactive_reply

Button tapped

A quick-reply button from /send-interactive-message was tapped.

event.interactive
{ "selectedId": "yes", "selectedDisplayText": "Yes" }
contact

Contact card shared

One or more vCards were shared.

event.contact
{ "contacts": [ { "displayName": "Jane Lim", "phones": ["+60123456789"], "vcard": "BEGIN:VCARD…" } ] }
  • body is a readable rendering: Contact shared\nName: …\nNumber: ….
location

Location

A pinned or live location.

event.location
{ "latitude": 3.139, "longitude": 101.6869, "name": "KLCC", "address": "Kuala Lumpur", "url": "", "isLive": false }
reaction

Reaction

An emoji reaction to an earlier message. Not a new message — update targetId.

event.reaction
{ "targetId": "3EB0…", "emoji": "👍" }
  • emoji: "" means the reaction was removed.
edit

Message edited

The sender edited an earlier message. Replace the body of targetId.

event.edit
{ "targetId": "3EB0…", "body": "Corrected text" }
revoke

Message deleted for everyone

The sender deleted an earlier message. Mark targetId as deleted.

event.revoke
{ "targetId": "3EB0…" }

Group messages

Delivered only when the session has group receiving enabled. Any of the types above can arrive with isGroup: true and this object:

event.group
{
  "jid": "[email protected]",
  "subject": "Launch team",
  "participant": "123456789012345",
  "participantPhone": "60123456789",
  "participantUsername": "janelim"
}

Note

chatRoomId for a group is <clientId>-<myLid>-<groupId> and remoteJid ends in @g.us. Reply in the group with to: group.jid, or privately with to: group.participant.