> ## Documentation Index
> Fetch the complete documentation index at: https://zapo.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Tipos de mensagem

> Cada variante de conteúdo de envio — os builders tipados discriminados por `type` e os campos brutos de Proto.IMessage que a biblioteca reconhece.

Tudo o que você envia passa por `client.message.send(to, content, options?)`. O argumento `content` é um `WaSendMessageContent`:

```ts theme={null}
type WaSendMessageContent =
  | string                        // atalho para uma mensagem de texto
  | WaSendTextMessage             // type: 'text'
  | WaSendReactionMessage         // type: 'reaction'
  | WaSendRevokeMessage           // type: 'revoke'
  | WaSendPinMessage              // type: 'pin' | 'unpin'
  | WaSendKeepMessage             // type: 'keep' | 'unkeep'
  | WaSendPollMessage             // type: 'poll'
  | WaSendPollVoteMessage         // type: 'poll-vote'
  | WaSendEventMessage            // type: 'event'
  | WaSendEventResponseMessage    // type: 'event-response'
  | WaSendMediaMessage            // type: 'image' | 'video' | 'ptv' | 'audio' | 'document' | 'sticker' | 'sticker-pack'
  | Proto.IMessage                // protobuf bruto — qualquer coisa não coberta acima
```

Existem duas maneiras de enviar: um **builder tipado** (um objeto com um discriminador `type` — a biblioteca valida e preenche os campos de protocolo para você) ou um **`Proto.IMessage` bruto** (você mesmo monta o protobuf). O mesmo `send()` aceita ambos.

<h2 id="shorthand">
  Atalho
</h2>

Uma string simples é enviada como uma mensagem de texto:

```ts theme={null}
await client.message.send(jid, 'Hello!')
```

<h2 id="typed-builders">
  Builders tipados
</h2>

Cada builder é discriminado pelo seu campo `type`. Campos em negrito são obrigatórios.

<h3 id="text--media">
  Texto e mídia
</h3>

| `type`         | Tipo                       | Campos obrigatórios                                                              | Guia                                                            |
| -------------- | -------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `text`         | `WaSendTextMessage`        | **`text`**                                                                       | [Enviando mensagens](/pt-br/guides/sending-messages#plain-text) |
| `image`        | `WaSendMediaMessage`       | **`media`** (mimetype opcional com um processor `detectMimetype`)                | [Mídia](/pt-br/guides/media#images)                             |
| `video`        | `WaSendMediaMessage`       | **`media`** (mimetype opcional com um processor `detectMimetype`)                | [Mídia](/pt-br/guides/media#video)                              |
| `ptv`          | `WaSendMediaMessage`       | **`media`** (mimetype opcional com um processor `detectMimetype`)                | [Mídia](/pt-br/guides/media#video)                              |
| `audio`        | `WaSendMediaMessage`       | **`media`** (mimetype opcional com um processor `detectMimetype`)                | [Mídia](/pt-br/guides/media#audio--voice-notes)                 |
| `document`     | `WaSendMediaMessage`       | **`media`** (mimetype opcional com um processor `detectMimetype`)                | [Mídia](/pt-br/guides/media#documents)                          |
| `sticker`      | `WaSendMediaMessage`       | **`media`** (mimetype padrão é `image/webp`)                                     | [Mídia](/pt-br/guides/media#stickers)                           |
| `sticker-pack` | `WaSendStickerPackMessage` | **`stickerPackId`**, **`name`**, **`publisher`**, **`stickers`**, **`trayIcon`** | [Mídia](/pt-br/guides/media#stickers)                           |

Os builders de mídia também aceitam qualquer campo não-gerenciado da mensagem protobuf subjacente (por exemplo `caption`, `gifPlayback`, `ptt`, `fileName`) via o mapeamento `UserMediaFields`. Campos gerenciados pelo protocolo (`url`, `mediaKey`, `fileSha256`, `directPath`, …) são preenchidos pelo builder.

`mimetype` é opcional. A ordem de resolução é: um `mimetype` explícito que você passa vence; senão o builder chama `media.processor.detectMimetype` (fornecido por `@zapo-js/media-utils` quando `file-type` está instalado); senão lança erro para `image`/`video`/`audio`/`document`/`ptv`. Stickers usam `image/webp` por padrão.

<h3 id="interactive">
  Interativos
</h3>

| `type`            | Tipo                         | Campos obrigatórios                      | Guia                                                                           |
| ----------------- | ---------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------ |
| `reaction`        | `WaSendReactionMessage`      | **`emoji`**, **`target`**                | [Reações](/pt-br/guides/interactive-messages#reactions)                        |
| `poll`            | `WaSendPollMessage`          | **`name`**, **`options`**                | [Enquetes](/pt-br/guides/interactive-messages#polls)                           |
| `poll-vote`       | `WaSendPollVoteMessage`      | **`poll`**, **`selectedOptionNames`**    | [Votação](/pt-br/guides/interactive-messages#voting-on-a-poll)                 |
| `event`           | `WaSendEventMessage`         | **`name`**, **`startTime`**              | [Eventos](/pt-br/guides/interactive-messages#events)                           |
| `event-response`  | `WaSendEventResponseMessage` | **`event`**, **`response`**              | [Resposta a evento](/pt-br/guides/interactive-messages#responding-to-an-event) |
| `pin` / `unpin`   | `WaSendPinMessage`           | **`target`** (+ `durationSecs` opcional) | [Fixar](/pt-br/guides/interactive-messages#pinning)                            |
| `keep` / `unkeep` | `WaSendKeepMessage`          | **`target`**                             | [Manter no chat](/pt-br/guides/interactive-messages#keep-in-chat)              |
| `revoke`          | `WaSendRevokeMessage`        | **`target`**                             | [Revogar](/pt-br/guides/interactive-messages#revoking-delete-for-everyone)     |

`target` é um `WaMessageTargetInput` — uma [`WaMessageKey`](/pt-br/guides/interactive-messages#targeting-a-message) (`{ remoteJid, id, fromMe, participant? }`) **ou** um evento `message` recebido passado literalmente (sua `key` é usada). Os pais de `poll`/`event` exigem adicionalmente `authorJid` e o `messageSecret` de 32 bytes.

Para `revoke`, sender vs admin é auto-detectado por `target.fromMe` (`false` dispara um admin revoke). Não há opção `subtype`.

<h2 id="raw-protoimessage">
  `Proto.IMessage` bruto
</h2>

Para qualquer coisa sem um builder tipado, passe uma mensagem protobuf bruta. A biblioteca inspeciona o campo preenchido e **resolve automaticamente** os atributos da stanza — `type` da mensagem (\[`resolveMessageTypeAttr`]), `type` de mídia, `polltype`, `event_type`, `view_once` e `edit` — então você só define o campo de conteúdo.

```ts theme={null}
import { proto } from 'zapo-js'

await client.message.send(jid, {
  conversation: 'A raw text message'
})
```

<h3 id="text">
  Texto
</h3>

| Campo                 | Notas                                                                                                          |
| --------------------- | -------------------------------------------------------------------------------------------------------------- |
| `conversation`        | Texto simples.                                                                                                 |
| `extendedTextMessage` | Texto com contexto (links, menções, respostas). Um `matchedText` não-vazio o torna uma mensagem de link/mídia. |

<h3 id="media">
  Mídia
</h3>

| Campo                                            | Tipo de mídia resolvido                 |
| ------------------------------------------------ | --------------------------------------- |
| `imageMessage`                                   | `image`                                 |
| `videoMessage`                                   | `video` (ou `gif` quando `gifPlayback`) |
| `ptvMessage`                                     | `ptv`                                   |
| `audioMessage`                                   | `audio` (ou `ptt` quando `ptt`)         |
| `documentMessage` / `documentWithCaptionMessage` | `document`                              |
| `stickerMessage`                                 | `sticker`                               |
| `stickerPackMessage`                             | `sticker-pack`                          |

<Note>
  Campos de mídia brutos exigem mídia previamente enviada (as chaves de criptografia, o `directPath` e os digests já devem estar definidos). Para enviar a partir de bytes/um arquivo, use os builders de mídia tipados em vez disso — eles realizam o upload para você.
</Note>

<h3 id="location--contacts">
  Localização e contatos
</h3>

```ts theme={null}
// Localização estática
await client.message.send(jid, {
  locationMessage: { degreesLatitude: -23.55, degreesLongitude: -46.63, name: 'HQ' }
})

// Localização ao vivo (resolvida como `live-location`)
await client.message.send(jid, {
  liveLocationMessage: { degreesLatitude: -23.55, degreesLongitude: -46.63 }
})

// Contato único (vCard)
await client.message.send(jid, {
  contactMessage: { displayName: 'Maria', vcard: 'BEGIN:VCARD\n...\nEND:VCARD' }
})

// Múltiplos contatos
await client.message.send(jid, {
  contactsArrayMessage: { displayName: 'Team', contacts: [/* IContactMessage[] */] }
})
```

| Campo                  | Tipo de mídia resolvido                         |
| ---------------------- | ----------------------------------------------- |
| `locationMessage`      | `location` (ou `live-location` quando `isLive`) |
| `liveLocationMessage`  | `live-location`                                 |
| `contactMessage`       | `vcard`                                         |
| `contactsArrayMessage` | `contact_array`                                 |

<h3 id="interactive--business">
  Interativos e business
</h3>

| Campo                              | Tipo resolvido         |
| ---------------------------------- | ---------------------- |
| `buttonsMessage`                   | `button`               |
| `buttonsResponseMessage`           | `button_response`      |
| `listMessage`                      | `list`                 |
| `listResponseMessage`              | `list_response`        |
| `interactiveMessage` (native flow) | interactive            |
| `interactiveResponseMessage`       | `native_flow_response` |
| `templateButtonReplyMessage`       | text                   |
| `orderMessage`                     | `order`                |
| `productMessage`                   | `product`              |
| `groupInviteMessage`               | `url`                  |

```ts theme={null}
await client.message.send(jid, {
  groupInviteMessage: {
    groupJid, inviteCode, inviteExpiration, groupName
  }
})
```

<h3 id="polls--events-raw">
  Enquetes e eventos (bruto)
</h3>

| Campo                                         | Resolvido                        |
| --------------------------------------------- | -------------------------------- |
| `pollCreationMessage` / `…V2` / `…V3` / `…V5` | `poll` (`polltype: creation`)    |
| `pollUpdateMessage`                           | `poll` (`polltype: vote`)        |
| `pollResultSnapshotMessage`                   | text                             |
| `eventMessage`                                | `event` (`event_type: creation`) |
| `encEventResponseMessage`                     | `event` (`event_type: response`) |

Mensagens de criação de enquete e de evento auto-persistem seu `messageSecret` para que votos/respostas posteriores possam ser criptografados.

<h3 id="protocol-edits--system">
  Protocolo, edições e sistema
</h3>

| Campo                                           | Notas                                                                                                      |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `protocolMessage`                               | Revogações (`REVOKE`), edições (`MESSAGE_EDIT`), sincronização ephemeral, requisições de welcome.          |
| `editedMessage`                                 | Wrapper de mensagem editada (atributo `edit`).                                                             |
| `reactionMessage` / `encReactionMessage`        | Reação (`type: reaction`); `text` vazio revoga.                                                            |
| `pinInChatMessage`                              | Fixar/desafixar (`edit: pin_in_chat`).                                                                     |
| `keepInChatMessage`                             | Manter no chat.                                                                                            |
| `encCommentMessage`                             | Comentário em uma mensagem.                                                                                |
| `requestPhoneNumberMessage`                     | Solicitar um número de telefone.                                                                           |
| `newsletterAdminInviteMessage`                  | Convite de admin de newsletter.                                                                            |
| `secretEncryptedMessage`                        | Carrega `secretEncType`: `EVENT_EDIT`, `POLL_EDIT`, `POLL_ADD_OPTION`, `MESSAGE_EDIT`, `MESSAGE_SCHEDULE`. |
| `messageHistoryNotice` / `messageHistoryBundle` | Compartilhamento de histórico de grupo.                                                                    |

<h3 id="wrappers">
  Wrappers
</h3>

Estes envolvem uma mensagem interna; a biblioteca os desembrulha ao resolver os atributos:

`ephemeralMessage`, `viewOnceMessage`, `viewOnceMessageV2`, `deviceSentMessage`, `groupMentionedMessage`, `botInvokeMessage`, `documentWithCaptionMessage`.

Para visualização única especificamente, prefira a [opção de envio `viewOnce`](/pt-br/guides/media#view-once) em vez de embrulhar manualmente.

<Tip>
  A superfície protobuf completa está disponível sob o namespace `proto` exportado — `proto.Message`, `proto.Message.ProtocolMessage.Type`, etc. Use-o para construir qualquer campo acima e para referenciar valores de enum.
</Tip>

<h2 id="raw-proto-cookbook">
  Cookbook de proto bruto
</h2>

Payloads concretos de `client.message.send(jid, …)` para os tipos brutos comuns. Importe `proto` para os valores de enum:

```ts theme={null}
import { proto } from 'zapo-js'
```

<h3 id="plain-text">
  Texto simples
</h3>

```ts theme={null}
await client.message.send(jid, { conversation: 'Hello' })
```

<h3 id="text-with-mentions--reply">
  Texto com menções + resposta
</h3>

```ts theme={null}
await client.message.send(jid, {
  extendedTextMessage: {
    text: 'Hey @5511999999999 👆',
    contextInfo: {
      mentionedJid: ['5511999999999@s.whatsapp.net'],
      // citação/resposta:
      stanzaId: originalStanzaId,
      participant: originalSenderJid,
      quotedMessage: { conversation: 'the quoted text' }
    }
  }
})
```

<h3 id="text-with-a-manual-link-preview">
  Texto com um preview de link manual
</h3>

```ts theme={null}
await client.message.send(jid, {
  extendedTextMessage: {
    text: 'https://example.com',
    matchedText: 'https://example.com',
    title: 'Example',
    description: 'Example domain'
  }
})
```

<h3 id="static-location">
  Localização estática
</h3>

```ts theme={null}
await client.message.send(jid, {
  locationMessage: {
    degreesLatitude: -23.5505,
    degreesLongitude: -46.6333,
    name: 'São Paulo',
    address: 'SP, Brazil'
  }
})
```

<h3 id="live-location">
  Localização ao vivo
</h3>

```ts theme={null}
await client.message.send(jid, {
  liveLocationMessage: {
    degreesLatitude: -23.5505,
    degreesLongitude: -46.6333,
    accuracyInMeters: 50,
    speedInMps: 0,
    caption: 'On my way',
    sequenceNumber: 1
  }
})
```

<h3 id="contact-card-vcard">
  Cartão de contato (vCard)
</h3>

```ts theme={null}
await client.message.send(jid, {
  contactMessage: {
    displayName: 'Maria Silva',
    vcard: [
      'BEGIN:VCARD',
      'VERSION:3.0',
      'FN:Maria Silva',
      'TEL;type=CELL;waid=5511999999999:+55 11 99999-9999',
      'END:VCARD'
    ].join('\n')
  }
})
```

<h3 id="multiple-contacts">
  Múltiplos contatos
</h3>

```ts theme={null}
await client.message.send(jid, {
  contactsArrayMessage: {
    displayName: 'My contacts',
    contacts: [
      { displayName: 'Maria', vcard: 'BEGIN:VCARD…END:VCARD' },
      { displayName: 'João', vcard: 'BEGIN:VCARD…END:VCARD' }
    ]
  }
})
```

<h3 id="group-invite">
  Convite de grupo
</h3>

```ts theme={null}
await client.message.send(jid, {
  groupInviteMessage: {
    groupJid: '123456789-987654@g.us',
    inviteCode: 'AbCdEf123',
    inviteExpiration: Math.floor(Date.now() / 1000) + 86_400,
    groupName: 'My group',
    caption: 'Join us!'
  }
})
```

<h3 id="buttons-raw">
  Botões (bruto)
</h3>

Até três botões de quick-reply. O header é um `oneof` — escolha texto, imagem, vídeo, localização ou documento (pré-upload pra mídia):

```ts theme={null}
await client.message.send(jid, {
  buttonsMessage: {
    contentText: 'Pedido feito — e agora?',
    footerText: 'Responda em 24h',
    headerType: proto.Message.ButtonsMessage.HeaderType.TEXT,
    text: 'Pedido #1234',
    buttons: [
      {
        buttonId: 'track',
        buttonText: { displayText: 'Rastrear' },
        type: proto.Message.ButtonsMessage.Button.Type.RESPONSE
      },
      {
        buttonId: 'cancel',
        buttonText: { displayText: 'Cancelar' },
        type: proto.Message.ButtonsMessage.Button.Type.RESPONSE
      }
    ]
  }
})
```

<h3 id="list-menu-raw">
  Menu de lista (bruto)
</h3>

Uma lista single-select de rows agrupadas em sections:

```ts theme={null}
await client.message.send(jid, {
  listMessage: {
    title: 'Cardápio',
    description: 'Escolha um item',
    buttonText: 'Ver cardápio',
    footerText: 'Aberto 9–18',
    listType: proto.Message.ListMessage.ListType.SINGLE_SELECT,
    sections: [
      {
        title: 'Pizzas',
        rows: [
          { rowId: 'pizza-margherita', title: 'Margherita', description: 'Tomate, mussarela, manjericão' },
          { rowId: 'pizza-pepperoni',  title: 'Pepperoni',  description: 'Tomate, queijo, pepperoni' }
        ]
      },
      {
        title: 'Bebidas',
        rows: [{ rowId: 'drink-cola', title: 'Cola' }]
      }
    ]
  }
})
```

<h3 id="interactive-native-flow-raw">
  Interactive native flow (bruto)
</h3>

A superfície interativa moderna — botões cujos parâmetros são payloads ad-hoc codificados em JSON:

```ts theme={null}
await client.message.send(jid, {
  interactiveMessage: {
    body: { text: 'Toque abaixo para abrir o form' },
    footer: { text: 'Powered by seu bot' },
    nativeFlowMessage: {
      buttons: [
        {
          name: 'cta_url',
          buttonParamsJson: JSON.stringify({
            display_text: 'Abrir form',
            url: 'https://example.com/form'
          })
        }
      ],
      messageVersion: 1
    }
  }
})
```

<h3 id="product-raw">
  Produto (bruto)
</h3>

Envie um produto do catálogo. O `productImage` interno precisa estar pré-uploadado:

```ts theme={null}
await client.message.send(jid, {
  productMessage: {
    businessOwnerJid: '5511999999999@s.whatsapp.net',
    body: 'Dá uma olhada nisso',
    footer: 'Em estoque',
    product: {
      productId: '12345',
      title: 'Chapéu',
      description: 'Tamanho único, ajustável',
      currencyCode: 'BRL',
      priceAmount1000: 49_900, // 49,90 BRL — preço × 1000
      retailerId: 'sku-001',
      url: 'https://example.com/p/12345',
      productImage: { /* campos de imagem pré-uploadados */ }
    }
  }
})
```

<h3 id="order-raw">
  Pedido (bruto)
</h3>

Confirmação / consulta de pedido:

```ts theme={null}
await client.message.send(jid, {
  orderMessage: {
    orderId: 'ord-abc',
    orderTitle: 'Pedido de exemplo',
    itemCount: 3,
    status: proto.Message.OrderMessage.OrderStatus.INQUIRY,   // ou ACCEPTED / DECLINED
    surface: proto.Message.OrderMessage.OrderSurface.CATALOG,
    sellerJid: '5511888888888@s.whatsapp.net',
    totalAmount1000: 149_700, // 149,70 BRL — total × 1000
    totalCurrencyCode: 'BRL',
    message: 'Detalhes do pedido'
  }
})
```

<h3 id="newsletter-admin-invite-raw">
  Convite de admin de newsletter (bruto)
</h3>

Convide um contato para ser co-admin de uma das suas newsletters:

```ts theme={null}
await client.message.send(contactJid, {
  newsletterAdminInviteMessage: {
    newsletterJid: '120363xxxxxxxxxxxxxx@newsletter',
    newsletterName: 'My Newsletter',
    caption: 'Vire co-admin',
    inviteExpiration: Math.floor(Date.now() / 1000) + 7 * 86_400
  }
})
```

<h3 id="reaction-raw">
  Reação (bruto)
</h3>

```ts theme={null}
await client.message.send(jid, {
  reactionMessage: {
    key: { remoteJid: jid, fromMe: false, id: targetStanzaId, participant: senderJid },
    text: '🔥', // string vazia remove a reação
    senderTimestampMs: Date.now()
  }
})
```

<h3 id="pin--unpin-raw">
  Fixar / desafixar (bruto)
</h3>

```ts theme={null}
await client.message.send(jid, {
  pinInChatMessage: {
    key: { remoteJid: jid, fromMe: false, id: targetStanzaId },
    type: proto.Message.PinInChatMessage.Type.PIN_FOR_ALL, // ou UNPIN_FOR_ALL
    senderTimestampMs: Date.now()
  }
})
```

<h3 id="keep--un-keep-in-chat-raw">
  Manter / desfazer manter no chat (bruto)
</h3>

```ts theme={null}
await client.message.send(jid, {
  keepInChatMessage: {
    key: { remoteJid: jid, fromMe: false, id: targetStanzaId },
    keepType: proto.KeepType.KEEP_FOR_ALL, // ou UNDO_KEEP_FOR_ALL
    timestampMs: Date.now()
  }
})
```

<h3 id="revoke--delete-for-everyone-protocolmessage">
  Revogar / apagar para todos (protocolMessage)
</h3>

```ts theme={null}
await client.message.send(jid, {
  protocolMessage: {
    key: { remoteJid: jid, fromMe: true, id: targetStanzaId },
    type: proto.Message.ProtocolMessage.Type.REVOKE
  }
})
```

<h3 id="toggle-disappearing-messages-ephemeral-setting">
  Alternar mensagens temporárias (configuração ephemeral)
</h3>

```ts theme={null}
await client.message.send(jid, {
  protocolMessage: {
    type: proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
    ephemeralExpiration: 7 * 24 * 3600 // segundos; 0 desabilita
  }
})
```

<h3 id="poll-raw">
  Enquete (bruto)
</h3>

```ts theme={null}
await client.message.send(jid, {
  pollCreationMessage: {
    name: 'Lunch?',
    options: [{ optionName: 'Pizza' }, { optionName: 'Sushi' }],
    selectableOptionsCount: 1
  }
})
```

<h3 id="request-a-phone-number">
  Solicitar um número de telefone
</h3>

```ts theme={null}
await client.message.send(jid, { requestPhoneNumberMessage: {} })
```

<h3 id="disappearing-wrapper-ephemeralmessage">
  Wrapper de mensagem temporária (ephemeralMessage)
</h3>

Envolva qualquer mensagem para que ela herde o timer ephemeral do chat:

```ts theme={null}
await client.message.send(jid, {
  ephemeralMessage: { message: { conversation: 'This disappears' } }
})
```

<h3 id="view-once-wrapper">
  Wrapper de visualização única
</h3>

```ts theme={null}
await client.message.send(jid, {
  viewOnceMessageV2: { message: { imageMessage: { /* pre-uploaded image fields */ } } }
})
```

<Note>
  Snippets que citam uma mensagem usam uma `key` de `{ remoteJid, fromMe, id, participant? }` (um `proto.IMessageKey`). Para os equivalentes tipados (reação, revogação, fixar, manter, enquete), prefira os [builders](#interactive) — eles gerenciam o message secret e o encadeamento da key para você.
</Note>
