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

# Envie e receba mensagens

> Envie texto, mídia e modelos, responda e reaja, e baixe mídia com o MessagingClient.

Envie mensagens por um Número conectado com `messaging.messages`. As mensagens
que você recebe chegam como webhooks.

| Tarefa | Permissão |
| - | - |
| Enviar, reagir, favoritar, marcar como vista, mostrar digitação | `messages:write` |
| Editar e excluir mensagens enviadas | `chats:manage` |
| Baixar mídia | `media:read` |
| Ler o histórico armazenado (beta) | `chats:read`, `messages:read` |

## Envie uma mensagem de texto

```typescript theme={null}
const sent = await messaging.messages.send("<number-id>", {
  conversation: { phoneNumber: "+15550001111" },
  content: { text: "Your order has shipped." },
});

console.log(sent.data.data.id, sent.data.data.status);
```

`conversation` escolhe o destinatário com um destes campos:

* `phoneNumber`: um número de telefone no formato E.164.
* `id`: o ID de conversa da Polymorfa de uma mensagem ou webhook anterior.
* `bsuid`: um ID de usuário com escopo da empresa (business-scoped user ID).

Se você passar mais de um, todos precisam apontar para a mesma conversa. Um nome
de usuário sozinho não é um destino.

`send` cria uma chave de idempotência para você, então as novas tentativas
automáticas dele nunca enviam duas vezes. Passe sua própria `idempotencyKey`
para continuar seguro entre reinícios do processo. Veja
[Tente novamente uma escrita com segurança](/pt-br/sdks/typescript/errors#tente-novamente-uma-escrita-com-segurança).

## Envie uma imagem ou um arquivo

```typescript theme={null}
await messaging.messages.send("<number-id>", {
  conversation: { phoneNumber: "+15550001111" },
  content: {
    image: { url: "https://example.com/receipt.png", caption: "Your receipt" },
  },
});

await messaging.messages.send("<number-id>", {
  conversation: { phoneNumber: "+15550001111" },
  content: {
    file: { url: "https://example.com/invoice.pdf", filename: "invoice.pdf" },
  },
});
```

Cada tipo de mídia (`image`, `video`, `file`, `voice`) recebe `url` ou
`base64`, nunca os dois. Defina `voice.ptt` como `true` para enviar uma mensagem
de voz.

## Envie um modelo

```typescript theme={null}
await messaging.messages.send("<number-id>", {
  conversation: { phoneNumber: "+15550001111" },
  content: {
    template: {
      name: "order_ready",
      language: "en_US",
      components: [
        { type: "body", parameters: [{ type: "text", text: "Ada" }] },
      ],
    },
  },
});
```

O modelo precisa estar aprovado nesse idioma; caso contrário, o envio falha com
`template_not_approved`. Em um Número da API oficial, uma mensagem livre enviada
mais de 24 horas depois da última mensagem do cliente falha com
`conversation_window_closed`; envie um modelo nesse caso. Veja
[Modelos](/pt-br/sdks/typescript/templates).

## Outros tipos de mensagem

`content` contém exatamente um tipo de mensagem. Além de texto, mídia e modelos,
os tipos do SDK abrangem `poll`, `location`, `contact`, `buttons`, `list`,
`product`, `productList`, `order`, `requestPhoneNumber`, `addressMessage`,
`flow` e `callPermissionRequest`. Seu editor lista os campos de cada tipo a
partir do tipo `SendMessageRequest`.

```typescript theme={null}
await messaging.messages.send("<number-id>", {
  conversation: { phoneNumber: "+15550001111" },
  content: {
    buttons: {
      body: "Confirm your appointment?",
      buttons: [
        { type: "reply", text: "Confirm", id: "confirm" },
        { type: "reply", text: "Reschedule", id: "reschedule" },
      ],
    },
  },
});
```

## Responda a uma mensagem

```typescript theme={null}
await messaging.messages.send("<number-id>", {
  conversation: { id: "<conversation-id>" },
  content: { text: "Thanks, we got it." },
  quotedMessage: { id: "<message-id>" },
});
```

Defina `isForwarded: true` para marcar uma mensagem como encaminhada.

## Reaja, marque como lida e mostre que está digitando

```typescript theme={null}
const conversation = { id: "<conversation-id>" };

await messaging.messages.react("<number-id>", { conversation, id: "<message-id>", reaction: "👍" });
await messaging.messages.markSeen("<number-id>", { conversation, id: "<message-id>" });
await messaging.messages.setTyping("<number-id>", { conversation, state: "typing", id: "<message-id>" });
```

Números da API oficial precisam do `id` de uma mensagem recebida para usar
`setTyping`. Eles marcam a mensagem como lida e mostram que estão digitando por
até 25 segundos ou até você responder. Eles aceitam apenas o estado `typing`.
Números com dispositivos vinculados também aceitam `recording` e `paused`.

## Edite ou exclua uma mensagem enviada

```typescript theme={null}
await messaging.chats.editMessage("<number-id>", "<conversation-id>", "<message-id>", {
  text: "Your order ships tomorrow.",
});

await messaging.chats.deleteMessage("<number-id>", "<conversation-id>", "<message-id>");
```

## IDs de mensagem

Toda mensagem tem um `id` da Polymorfa. Use-o para respostas, reações, edições
e exclusões. Mantenha-o como string, mesmo quando ele tiver apenas dígitos.

`whatsapp_ids` contém as referências do WhatsApp que a Polymorfa observou, em
`linked_devices`, `official_api` ou ambos. Elas não são intercambiáveis com o
`id` da Polymorfa. O campo antigo `whatsapp_id` está obsoleto; leia
`whatsapp_ids` no lugar dele. Veja
[Identificadores de mensagem](/guides/messaging/overview#message-identifiers).

## Receba mensagens

As mensagens recebidas chegam como webhooks `message.received`. Verifique a
assinatura e depois restrinja o tipo do evento:

```typescript theme={null}
import { isEvent, webhooks } from "@polymorfa/sdk";

export async function handleWebhook(body: ArrayBuffer, signature: string, secret: string) {
  const event = await webhooks.verify({ body, signature, secret });

  if (isEvent(event, "message.received")) {
    console.log(event.session, event.payload);
  }
}
```

Veja [Webhooks](/pt-br/sdks/typescript/webhooks) para criar o endpoint e
verificar as solicitações. Para ler eventos sem um endpoint público, veja
[Eventos](/pt-br/sdks/typescript/events).

## Baixe mídia

Faça o streaming de um arquivo de mídia pelo ID de mídia da Polymorfa:

```typescript theme={null}
const download = await messaging.media.downloadStream("<media-id>");
console.log(download.contentType, download.filename);
// download.body is a ReadableStream<Uint8Array>. Read it once.
```

No Node.js, grave-o direto em um arquivo:

```typescript theme={null}
import { downloadMediaToFile } from "@polymorfa/sdk/node";

await downloadMediaToFile(messaging.media, "<media-id>", "./attachment.bin", {
  maxBytes: 50 * 1024 * 1024,
});
```

O helper grava em um arquivo temporário e só o move para o lugar final depois
que o download termina. Trate `filename` como nome de exibição, não como
caminho.

Quando um projeto não armazena mídia, os webhooks de mídia recebida trazem um
descritor `media` criptografado no lugar. `messaging.media.downloadFromWhatsApp(event.payload)`
baixa e descriptografa o arquivo do WhatsApp sem chamar a API da Polymorfa. O
descritor contém uma chave de descriptografia, então nunca registre em log os
corpos de webhook armazenados.

## Leia o histórico de mensagens armazenado

> [!NOTE]
>
> O histórico de mensagens está em beta. Ele funciona apenas para Números com o
> armazenamento hospedado de mensagens ativado, em equipes inscritas no beta. Veja
> [Leia o histórico de mensagens](/pt-br/guides/messaging/message-history).

```typescript theme={null}
const page = await messaging.chats.listMessages("<number-id>", "+15550001111", {
  limit: 50,
  order: "desc",
});

for (const message of page.data.data) console.log(message.id, message.text);

if (page.data.hasMore && page.data.nextCursor) {
  const older = await messaging.chats.listMessages("<number-id>", "+15550001111", {
    cursor: page.data.nextCursor,
    order: "desc",
  });
  console.log(older.data.data.length);
}
```

`chats.list` lista as conversas armazenadas. `chats.downloadMessageMediaStream`
baixa a cópia armazenada da mídia de uma mensagem e também precisa de
`media:read`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.