Skip to main content
For content types WhatsApp supports but zapo doesn’t wrap in a typed builder yet, client.message.send also accepts a raw Proto.IMessage. Fill the field that names the content type — locationMessage, contactMessage, contactsArrayMessage, interactiveMessage, and so on — and the library encodes it verbatim. Kinds that already have a typed builder — polls, reactions, edits, revokes, pins, keep-in-chat, view-once wrapping, and quotes / mentions / link previews — belong in Sending messages and Interactive messages. This page is for the raw-only kinds. The full set of recognized Proto.IMessage fields (location, live location, contacts, group invite, product, order, …) is listed in the message types reference. Some examples below use enum values from the proto namespace:

How the stanza type is resolved

Whatever field you fill, zapo classifies the message before it goes on the wire: a <message> stanza carries a type (text or media), and a media stanza must also carry a mediatype. The server silently drops a media stanza with no mediatype — the send acks fine and nothing ever arrives — so a content type that falls through to the media default without one is invisibly lost. Two details matter when you hand-build a payload:
  • Wrappers are descended into. deviceSentMessage, botForwardedMessage, groupStatusMessageV2 and groupStatusMessage all carry the real message in .message, so the inner content decides the type. A forwarded image stays media with its mediatype; an image status wrapped in groupStatusMessageV2 no longer goes out as type="media" with no mediatype — a pairing no real client sends.
  • The AI rich-response family classifies as text. richResponseMessage and a bare botForwardedMessage wrapper resolve to type="text". Before 1.9.0 they fell through to the media default and never delivered.

Locations

name and address are optional. For a live-location message, use the liveLocationMessage field instead — it carries movement metadata (accuracyInMeters, speedInMps, sequenceNumber).

Contacts

A single contact card is a contactMessage with a vCard string:
The waid=<digits> parameter on the TEL line is what lets the WhatsApp client link the card back to a WhatsApp account — use the recipient’s E.164 phone number without the +. For multiple cards at once, use contactsArrayMessage:

Group invite

Buttons

Up to three quick-reply buttons. The header is a oneof — pick text, image, video, location, or document (pre-uploaded for media):

List menu

A single-select list of rows grouped into sections:
A list to a group goes out with a different stanza shape than the same list in a direct chat: the group takes it only when type=media, mediatype=list and the <biz><list> companion node travel together, while a direct send keeps the flat text shape. zapo picks the right one for you. Before 1.10.0 a group list was nacked with 479 while the identical message went through 1:1.

Interactive native flow (cta_url)

The modern interactive surface — buttons whose params are JSON-encoded ad-hoc payloads:
This is the same wire shape as the PIX / review-and-pay cards in Payments below — only the button name and buttonParamsJson differ.

Product

Send a catalog product. The inner productImage must already be uploaded:

Order

Order confirmation / inquiry:

Newsletter admin invite

Invite a contact to co-admin one of your newsletters:

Toggle disappearing messages (ephemeral setting)

Chat-wide toggle for disappearing messages — distinct from the per-message expirationSeconds send option (one message) and the ephemeralMessage wrapper (one message inheriting the chat timer). This one flips the timer for the whole chat.

Request a phone number

Payments (PIX & review-and-pay)

Send WhatsApp Business payment cards — static PIX (payment_info) and order checkout (review_and_pay) — as raw interactiveMessage / nativeFlowMessage payloads through client.message.send. There is no typed builder for them yet, so build the shape yourself the same way as the locations/contacts cards above. The library relays the interactive native-flow buttons; the WhatsApp clients render the card UI.
Payment cards are a Business / native-flow feature. Rendering differs between WhatsApp mobile and WhatsApp Web — prefer the flow that matches the UI you want (payment_info for a PIX-only card, review_and_pay for the “Nº da cobrança” / order card) and verify on both clients.
Amounts are integer minor units plus an offset divisor: { value: 1000, offset: 100 } renders as R$ 10,00. PIX key_type is one of EVP (chave aleatória), EMAIL, PHONE (E.164 preferred), CPF, CNPJ.

PIX card (payment_info)

Renders the PIX payment card (key / merchant). Use this for a static PIX key without an order card.

Review-and-pay card (review_and_pay)

Renders the order / cobrança card (reference number, items, total). Use this for a checkout-style summary.
buttonParamsJson must be a JSON string — build the object in code and stringify it. body / footer on interactiveMessage are optional. Don’t mix payment_info and review_and_pay expecting the same UI — they render different cards, and adding extra cta_copy / CTA buttons in the same nativeFlowMessage can render differently on mobile vs Web.

See also

Last modified on October 8, 2026