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 the common raw kinds. Import proto for enum values:

Plain text

Text with mentions + reply

Static location

Live location

Contact card (vCard)

Multiple contacts

Group invite

Buttons (raw)

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

List menu (raw)

A single-select list of rows grouped into sections:

Interactive native flow (raw)

The modern interactive surface — buttons whose params are JSON-encoded ad-hoc payloads:

Product (raw)

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

Order (raw)

Order confirmation / inquiry:

Newsletter admin invite (raw)

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

Reaction (raw)

Pin / unpin (raw)

Keep / un-keep in chat (raw)

Revoke / delete-for-everyone (protocolMessage)

Toggle disappearing messages (ephemeral setting)

Poll (raw)

Request a phone number

Disappearing wrapper (ephemeralMessage)

Wrap any message so it inherits the chat’s ephemeral timer:

View-once wrapper

Snippets that quote a message use a key of { remoteJid, fromMe, id, participant? } (a proto.IMessageKey). For the typed equivalents (reaction, revoke, pin, keep, poll) prefer the builders — they manage the message secret and key wiring for you.
Last modified on June 3, 2026