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

# Enviar Mensagem

> Endpoint POST para envio de mensagens de texto, imagem, áudio, documento e lista de opções via API, com suporte a fila inteligente, atribuição de operador e controle do agente de IA.

# Enviar Mensagem

Envie mensagens programaticamente via WhatsApp.

```
POST https://wapi.stegia.com.br/functions/v1/send-message
```

<Note>
  Para **gerenciar contatos** (criar, atualizar, etiquetar) ou **gerenciar conversas** (atribuir, mudar status, adicionar notas) sem enviar mensagem, prefira os endpoints dedicados:

  * 📇 [API de Contatos](/api/contatos) — criar, atualizar, gerenciar tags
  * 💬 [API de Conversas](/api/conversacoes) — atribuir operador, mudar status, notas internas

  Os parâmetros `assignTo` e `portfolio` neste endpoint continuam funcionando para retrocompatibilidade.
</Note>

## Parâmetros do Body

| Campo             | Tipo    | Obrigatório | Descrição                                                                                                                                                    |
| ----------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `instanceId`      | string  | ✅           | ID da instância WhatsApp no Brainchat                                                                                                                        |
| `phone`           | string  | ✅           | Número do destinatário (formato: `5511999999999`)                                                                                                            |
| `messageType`     | string  | Depende     | Tipo: `text`, `image`, `audio`, `document`, `option_list`. Obrigatório apenas se enviar mensagem                                                             |
| `message`         | string  | Depende     | Texto da mensagem ou legenda da mídia                                                                                                                        |
| `mediaUrl`        | string  | Depende     | URL pública HTTPS do arquivo de mídia                                                                                                                        |
| `mediaFilename`   | string  | ❌           | Nome do arquivo para documentos (ex: `relatorio.pdf`)                                                                                                        |
| `optionList`      | object  | Depende     | Objeto com título, botão e opções — obrigatório para `messageType: "option_list"`                                                                            |
| `cardId`          | string  | ❌           | Identificador customizado para rastreamento                                                                                                                  |
| `delayMessage`    | number  | ❌           | Delay em segundos antes do envio                                                                                                                             |
| `delayTyping`     | number  | ❌           | Tempo em ms de simulação de digitação antes do envio                                                                                                         |
| `assignTo`        | string  | ❌           | E-mail ou UUID do operador para atribuir a conversa                                                                                                          |
| `portfolio`       | boolean | ❌           | Se `true`, adiciona o contato à carteira do operador com prioridade absoluta                                                                                 |
| `queued`          | boolean | ❌           | Se `true`, a mensagem entra na fila inteligente em vez de envio imediato                                                                                     |
| `intervalSeconds` | number  | ❌           | Intervalo em segundos entre mensagens na fila (padrão: 30s, min: 10s, max: 3600s)                                                                            |
| `sentBy`          | string  | ❌           | Origem da mensagem: `ai_agent`, `api`, `scheduled`, `automation`, `operator`, ou qualquer string. Se diferente de `ai_agent`, pausa o agente de IA por 30min |

## Exemplos

<Tabs>
  <Tab title="Texto">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "text",
      "message": "Olá! Como posso ajudar?"
    }
    ```
  </Tab>

  <Tab title="Mídia">
    **Imagem:**

    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "image",
      "mediaUrl": "https://exemplo.com/imagem.jpg",
      "message": "Legenda opcional"
    }
    ```

    **Áudio:**

    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "audio",
      "mediaUrl": "https://exemplo.com/audio.mp3"
    }
    ```

    **Documento:**

    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "document",
      "mediaUrl": "https://exemplo.com/documento.pdf",
      "message": "Relatório Mensal.pdf",
      "mediaFilename": "Relatório Mensal.pdf"
    }
    ```
  </Tab>

  <Tab title="Lista de Opções">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "option_list",
      "message": "Selecione uma opção:",
      "optionList": {
        "title": "Opções disponíveis",
        "buttonLabel": "Ver opções",
        "options": [
          {
            "id": "1",
            "title": "Suporte Técnico",
            "description": "Problemas técnicos e bugs"
          },
          {
            "id": "2",
            "title": "Vendas",
            "description": "Informações sobre produtos"
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="Fila Inteligente">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "text",
      "message": "Promoção especial para você!",
      "queued": true,
      "intervalSeconds": 60
    }
    ```

    <Info>
      Com `queued: true`, a mensagem entra na **fila inteligente** em vez de ser enviada imediatamente.
      O sistema calcula automaticamente o próximo horário disponível respeitando o intervalo configurado (`intervalSeconds`).

      **Comportamento da fila:**

      * Intervalo mínimo: **10 segundos**, máximo: **3600 segundos** (1 hora), padrão: **30 segundos**
      * Janela de envio padrão: **08:00 às 20:00** (horário da instância)
      * Mensagens fora do horário são agendadas para o próximo dia útil
      * O enfileiramento é **atômico** — advisory locks garantem que múltiplas chamadas simultâneas não conflitem
    </Info>
  </Tab>

  <Tab title="Atribuição sem Mensagem">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "assignTo": "joao@empresa.com",
      "portfolio": true
    }
    ```

    <Info>
      Quando `assignTo` está presente mas **não há `message` nem `mediaUrl`**, nenhuma mensagem é enviada ao WhatsApp — apenas a atribuição é feita.

      * Não é necessário informar `messageType`
      * O operador recebe o **e-mail de notificação** normalmente
      * Com `portfolio: true`, o contato é adicionado à carteira do operador
      * A resposta retorna `"mode": "assign_only"` confirmando que apenas a atribuição foi realizada
    </Info>
  </Tab>

  <Tab title="Atribuição com Mensagem">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "text",
      "message": "Olá! Você será atendido pelo João.",
      "assignTo": "joao@empresa.com",
      "portfolio": true
    }
    ```

    <Info>
      O parâmetro `assignTo` aceita **e-mail** ou **UUID** do operador.

      * Com `portfolio: true` (opcional), o contato é adicionado à **carteira do operador** com prioridade absoluta — somente ele verá esse contato.
      * O operador recebe automaticamente um **e-mail de notificação** com o nome do contato e um link direto para a conversa no chat.
      * Se o contato não existir, ele é **criado automaticamente** com os dados disponíveis.
      * A reatribuição registra automaticamente uma transferência no histórico e insere uma nota interna na conversa.
    </Info>
  </Tab>

  <Tab title="Controle do Agente">
    ```json theme={null}
    {
      "instanceId": "SUA_INSTANCIA",
      "phone": "5511999999999",
      "messageType": "text",
      "message": "Mensagem enviada via integração externa.",
      "sentBy": "api"
    }
    ```

    <Warning>
      O parâmetro `sentBy` controla se o **agente de IA ativo na instância** será pausado após o envio.
      Não é necessário informar o `agentId` — o sistema detecta automaticamente o agente vinculado à instância.

      A lógica é simples: **qualquer valor diferente de `ai_agent` pausa o agente por 30 minutos**.

      * `sentBy: "ai_agent"` → O agente **não é pausado** (a mensagem é tratada como resposta do próprio agente)
      * `sentBy: "api"` → O agente é **pausado por 30 minutos** (integração externa — valor mais comum)
      * `sentBy: "operator"` → O agente é **pausado por 30 minutos** (mensagem humana)
      * `sentBy: "automation"` → O agente é **pausado por 30 minutos**
      * `sentBy: "scheduled"` → O agente é **pausado por 30 minutos**
      * Sem `sentBy` → Comportamento padrão, o agente é pausado

      A cada nova mensagem com `sentBy` diferente de `ai_agent`, o timer de 30 minutos é **renovado**.
    </Warning>
  </Tab>
</Tabs>

<Note>
  Todos os parâmetros podem ser **combinados livremente** em uma única chamada. Por exemplo, é possível enviar uma mensagem com fila inteligente (`queued`), atribuição (`assignTo` + `portfolio`) e controle do agente (`sentBy`) ao mesmo tempo.
</Note>

## cURL Completo

```bash theme={null}
curl -X POST "https://wapi.stegia.com.br/functions/v1/send-message" \
  -H "Content-Type: application/json" \
  -H "X-Client-Token: SEU_TOKEN_AQUI" \
  -d '{
    "instanceId": "SUA_INSTANCIA",
    "phone": "5511999999999",
    "messageType": "text",
    "message": "Olá! Esta é uma mensagem via API."
  }'
```

## Comportamentos Automáticos

<AccordionGroup>
  <Accordion title="Fila Inteligente (queued)">
    Quando `queued: true`, o sistema usa **enfileiramento atômico** com advisory locks para calcular o próximo horário de envio:

    1. Verifica o último envio para aquela instância
    2. Calcula `próximo_envio = MAX(agora, último_envio + intervalo)`
    3. Agenda a mensagem com o horário calculado
    4. Um worker (QStash + pg\_cron) processa a fila automaticamente

    **Limites de velocidade:** O intervalo configurável (`intervalSeconds`) garante que mensagens não sejam enviadas em rajada, evitando banimentos do WhatsApp.

    **Janela de horário:** Por padrão, mensagens são enviadas entre 08:00 e 20:00 no fuso da instância. Mensagens agendadas fora desse horário são postergadas.
  </Accordion>

  <Accordion title="Pausa do Agente de IA">
    Se a instância possui um agente de IA ativo, mensagens enviadas via API com `sentBy` diferente de `ai_agent` **pausam automaticamente** o agente por 30 minutos para aquele contato específico.

    Isso evita que o agente responda sobre uma mensagem enviada manualmente por um operador ou automação. A cada nova mensagem humana, o timer de pausa é **renovado**.

    Para enviar mensagens via API **sem pausar** o agente (ex: respostas automáticas do próprio agente), use `sentBy: "ai_agent"`.

    **Qualquer string** diferente de `ai_agent` pausa o agente — os valores `api`, `operator`, `automation`, `scheduled` são apenas convenções para facilitar a rastreabilidade.
  </Accordion>

  <Accordion title="Notificação ao Operador">
    Quando um contato é atribuído via `assignTo`, o operador recebe automaticamente um **e-mail** contendo:

    * Nome do contato (ou número, se sem nome)
    * Telefone do contato
    * **Link direto** para abrir a conversa no chat (`/c/chat/{telefoneInstância}/{telefoneContato}`)

    O e-mail é enviado de forma assíncrona (fire-and-forget) e não bloqueia o envio da mensagem.
  </Accordion>

  <Accordion title="Auto-criação de Contato">
    Se o número informado em `phone` não existir na base de contatos da instância, o sistema **cria automaticamente** um novo contato com os dados disponíveis antes de enviar a mensagem.
  </Accordion>
</AccordionGroup>

## Informações Importantes

<CardGroup cols={2}>
  <Card title="Formato do Telefone" icon="phone">
    Sempre com código do país: `5511999999999`. Use o endpoint [Sanitizar Número](#post--sanitizar-número) para normalizar.
  </Card>

  <Card title="Tipos de Mídia" icon="paperclip">
    JPG, PNG, MP3, WAV, MP4, PDF — URLs devem ser públicas e HTTPS.
  </Card>
</CardGroup>

***

## Iniciar Conversa com Agente de IA

<Note>
  Este é um **endpoint diferente** do `send-message`. Use-o para acionar o agente de IA proativamente — ele envia a primeira mensagem como se fosse o agente e cria a conversa automaticamente.
</Note>

```
POST https://wapi.stegia.com.br/functions/v1/process-ai-agent
```

### Parâmetros do Body

| Campo                  | Tipo    | Obrigatório | Descrição                                                                                                                           |
| ---------------------- | ------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `instanceId`           | string  | ✅           | ID da instância (UUID ou embed\_key)                                                                                                |
| `phone`                | string  | ✅           | Número do destinatário (formato: `5511999999999`)                                                                                   |
| `messageText`          | string  | ✅           | Texto da primeira mensagem enviada como o agente                                                                                    |
| `agentId`              | string  | ❌           | UUID do agente (obrigatório se a instância tiver múltiplos agentes)                                                                 |
| `initiateConversation` | boolean | ✅           | Deve ser `true` para modo proativo                                                                                                  |
| `externalContext`      | object  | ❌           | Dados externos injetados na conversa — ficam disponíveis como variáveis em `collected_data` para o agente referenciar dinamicamente |
| `queued`               | boolean | ❌           | Se `true`, a mensagem entra na fila inteligente                                                                                     |
| `intervalSeconds`      | number  | ❌           | Intervalo em segundos entre mensagens na fila                                                                                       |
| `sentBy`               | string  | ❌           | Origem da mensagem (padrão: `api`)                                                                                                  |

### Exemplo

```json theme={null}
{
  "instanceId": "emb_5434740aa6ed1856",
  "phone": "5511999999999",
  "messageText": "Olá! Somos da empresa X e gostaríamos de falar sobre seu cadastro.",
  "agentId": "c365ac34-4704-41cb-adbe-52f72221c79a",
  "initiateConversation": true,
  "queued": true,
  "intervalSeconds": 30,
  "sentBy": "api",
  "externalContext": {
    "nome_cliente": "João Silva",
    "valor_pendente": "R$1.500,00",
    "id_pedido": "12345"
  }
}
```

<Info>
  **Como funciona:**

  * A mensagem é enviada **como se fosse o agente** (não como operador humano)
  * A conversa é criada automaticamente no sistema com o agente vinculado
  * O agente só processa IA quando o contato **responder** — a primeira mensagem é enviada diretamente
  * `externalContext` injeta variáveis externas que são armazenadas em `collected_data` — o agente pode referenciar essas variáveis durante toda a conversa (ex: `nome_cliente`, `valor_pendente`, `id_pedido`)
  * Ideal para **integrações com CRMs** (Pipefy, HubSpot, etc.) onde o agente precisa de contexto externo para conduzir a conversa
  * Se o contato não existir, ele é **criado automaticamente**
</Info>

### cURL

```bash theme={null}
curl -X POST "https://wapi.stegia.com.br/functions/v1/process-ai-agent" \
  -H "Content-Type: application/json" \
  -H "X-Client-Token: SEU_TOKEN_AQUI" \
  -d '{
    "instanceId": "emb_5434740aa6ed1856",
    "phone": "5511999999999",
    "messageText": "Olá! Gostaríamos de falar sobre seu cadastro.",
    "agentId": "SEU_AGENT_ID",
    "initiateConversation": true,
    "sentBy": "api"
  }'
```

***

## Endpoints Auxiliares

### GET — Histórico de Mensagens

Recupere o histórico de mensagens para contexto de IA ou auditoria.

```
GET https://wapi.stegia.com.br/functions/v1/messages-context
```

**Parâmetros (query string):**

| Parâmetro    | Obrigatório | Descrição                         |
| ------------ | ----------- | --------------------------------- |
| `phone`      | ✅           | Número do telefone                |
| `start`      | ✅           | Data inicial (YYYY-MM-DD)         |
| `end`        | ✅           | Data final (YYYY-MM-DD)           |
| `instanceId` | ✅           | ID da instância                   |
| `limit`      | ❌           | Máximo de mensagens (padrão: 100) |
| `format`     | ❌           | `conversation` ou `raw`           |

```bash theme={null}
curl -X GET "https://wapi.stegia.com.br/functions/v1/messages-context?phone=5511999999999&start=2024-01-01&end=2024-12-31&instanceId=SUA_INSTANCIA" \
  -H "X-Client-Token: SEU_TOKEN_AQUI"
```

### POST — Sanitizar Número

Endpoint público (sem token) que remove formatação de telefones.

```
POST https://wapi.stegia.com.br/functions/v1/sanitize-phone-number
```

```bash theme={null}
curl -X POST "https://wapi.stegia.com.br/functions/v1/sanitize-phone-number" \
  -H "Content-Type: application/json" \
  -d '{"phone": "(11) 99999-9999"}'
```

**Resposta:**

```json theme={null}
{
  "success": true,
  "original": "(11) 99999-9999",
  "sanitized": "11999999999"
}
```
