Skip to main content
Everything you send goes through client.message.send(to, content, options?). The content argument is a WaSendMessageContent:
There are two ways to send: a typed builder (an object with a type discriminator — the library validates and fills protocol fields for you) or a raw Proto.IMessage (you build the protobuf yourself). The same send() accepts both.

Shorthand

A plain string is sent as a text message:

Typed builders

Each builder is discriminated by its type field. Bold fields are required.

Text & media

Media builders also accept any non-managed field of the underlying protobuf message (e.g. caption, gifPlayback, ptt, fileName) via the UserMediaFields mapping. Protocol-managed fields (url, mediaKey, fileSha256, directPath, …) are filled by the builder. mimetype is optional. The resolution order is: an explicit mimetype you pass wins; otherwise the builder calls media.processor.detectMimetype (provided by @zapo-js/media-utils when file-type is installed); otherwise it throws for image/video/audio/document/ptv. Stickers default to image/webp.

Interactive

target is a WaMessageTargetInput — a WaMessageKey ({ remoteJid, id, fromMe, participant? }) or a received message event passed verbatim (its key is used). poll/event parents additionally require authorJid and the 32-byte messageSecret. For revoke, sender-vs-admin is auto-detected from target.fromMe (false triggers an admin revoke). There is no subtype option.

Raw Proto.IMessage

For anything without a typed builder, pass a raw protobuf message. The library inspects the populated field and automatically resolves the stanza attributes — message type ([resolveMessageTypeAttr]), media type, polltype, event_type, view_once, and edit — so you only set the content field.

Text

Media

Raw media fields require pre-uploaded media (the encryption keys, directPath, and digests must already be set). To upload from bytes/a file, use the typed media builders instead — they perform the upload for you.

Location & contacts

Interactive & business

Polls & events (raw)

Poll creation and event messages auto-persist their messageSecret so later votes/responses can be encrypted.

Protocol, edits & system

Wrappers

These wrap an inner message; the library unwraps them when resolving attributes: ephemeralMessage, viewOnceMessage, viewOnceMessageV2, deviceSentMessage, groupMentionedMessage, botInvokeMessage, documentWithCaptionMessage. For view-once specifically, prefer the viewOnce send option over hand-wrapping.
The full protobuf surface is available under the exported proto namespace — proto.Message, proto.Message.ProtocolMessage.Type, etc. Use it to build any field above and to reference enum values.

Raw proto cookbook

Concrete client.message.send(jid, …) payloads for every raw kind live in the Raw proto sends guide. This reference only carries the type-mapping tables above; the guide has the send examples plus payment cards (PIX / review-and-pay).

Disappearing wrapper (ephemeralMessage)

Wrap any message so it inherits the chat’s ephemeral timer. This is a wrapper mechanic — the inner message is what actually renders:
For the chat-wide ephemeral toggle (protocolMessage + EPHEMERAL_SETTING), see the guide’s Toggle disappearing messages section.
Last modified on August 19, 2026