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

# Enviar mensagens

> Como enviar mensagens pela API do Connecta DESK: os quatro tipos de mensagem, a resposta 202 com jobId e a consulta do resultado.

`POST /messages` envia os quatro tipos de mensagem. A API responde na hora com `202` e um `jobId`,
e faz o envio em segundo plano. Depois você consulta o `jobId` para saber se a mensagem saiu.

## O fluxo

<Steps>
  <Step title="Descubra o canal de saída">
    Todo envio precisa de um `channelId`. Liste os canais conectados da empresa:

    ```bash theme={null}
    curl --request GET \
      --url "$CONNECTA_URL/channels" \
      --header "Authorization: Bearer $CONNECTA_TOKEN"
    ```

    Guarde o id na configuração da sua integração. Ele quase nunca muda, e buscar a lista a cada
    envio gasta o seu [limite por minuto](/essentials/limites-de-uso) sem necessidade.
  </Step>

  <Step title="Envie">
    ```bash theme={null}
    curl --request POST \
      --url "$CONNECTA_URL/messages" \
      --header "Authorization: Bearer $CONNECTA_TOKEN" \
      --header "Content-Type: application/json" \
      --header "Idempotency-Key: pedido-88213-confirmacao" \
      --data '{
        "channelId": 4,
        "type": "text",
        "number": "5511999999999",
        "body": "Seu pedido #88213 foi confirmado."
      }'
    ```

    A resposta chega na hora:

    ```json theme={null}
    {
      "data": { "jobId": "5512", "status": "queued" }
    }
    ```

    <Tip>
      Sempre envie `Idempotency-Key` neste endpoint. Se a chamada der timeout e você tentar de
      novo sem a chave, o cliente pode receber a mensagem duas vezes. Veja
      [Idempotência](/essentials/idempotencia).
    </Tip>
  </Step>

  <Step title="Confirme o resultado">
    ```bash theme={null}
    curl --request GET \
      --url "$CONNECTA_URL/messages/jobs/5512" \
      --header "Authorization: Bearer $CONNECTA_TOKEN"
    ```

    ```json theme={null}
    {
      "data": {
        "jobId": "5512",
        "status": "sent",
        "attempts": 1,
        "ticketId": 9034,
        "providerMessageId": "wamid.HBgNNTUxMTk5OTk5OTk5ORUCABEYEjhBMkI…",
        "failedReason": null
      }
    }
    ```

    Guarde o `ticketId`. Com ele você acompanha a conversa dali em diante, usando
    `GET /tickets/{ticketId}/messages`.
  </Step>
</Steps>

## Estados do job

<ResponseField name="queued" type="status">
  Aceito e aguardando processamento.
</ResponseField>

<ResponseField name="processing" type="status">
  Sendo enviado ao provedor.
</ResponseField>

<ResponseField name="sent" type="status">
  Entregue ao provedor. O campo `providerMessageId` traz o identificador que o provedor deu à
  mensagem.
</ResponseField>

<ResponseField name="failed" type="status">
  O envio falhou. `failedReason` explica o motivo e `attempts` mostra quantas vezes o envio foi
  tentado.
</ResponseField>

<Note>
  **Contatos ativos no mês.** O plano tem um limite de contatos ativos por mês: um contato conta
  uma vez, na primeira mensagem trocada com a empresa no mês (enviada ou recebida), e a contagem
  zera no dia 1º. Com o limite atingido, contatos que já contaram seguem recebendo normalmente; uma
  mensagem a um contato novo é recusada na chamada com `402 ERR_API_ACTIVE_CONTACTS_LIMIT_REACHED`.
  Se o limite acabar entre a chamada e o envio, o job termina em `failed` com
  `failedReason: ERR_MAX_ACTIVE_CONTACTS_BY_MONTH_REACHED`. Canais `web_whatsapp` não são
  limitados.
</Note>

<Warning>
  `sent` quer dizer que o **provedor aceitou** a mensagem. Ainda não significa que o destinatário
  recebeu ou leu. A confirmação de entrega e de leitura chega depois, no status da mensagem dentro
  do atendimento.
</Warning>

Ao consultar o job, comece com 1 segundo de intervalo entre as consultas e vá dobrando esse tempo.
Consultas seguidas, sem pausa, gastam todo o limite por minuto em poucos segundos.

## Os quatro tipos

<Tabs>
  <Tab title="text">
    É o tipo padrão. Além do destinatário, só o `body` é obrigatório.

    ```json theme={null}
    {
      "channelId": 4,
      "type": "text",
      "number": "5511999999999",
      "body": "Olá, {{name}}! Seu protocolo é 88213."
    }
    ```

    O campo `body` aceita variáveis do sistema, como `{{name}}`.
  </Tab>

  <Tab title="media">
    O envio precisa ser em `multipart/form-data`, com o arquivo anexado. O `body` vira a legenda.

    ```bash theme={null}
    curl --request POST \
      --url "$CONNECTA_URL/messages" \
      --header "Authorization: Bearer $CONNECTA_TOKEN" \
      --form channelId=4 \
      --form type=media \
      --form number=5511999999999 \
      --form 'body=Segue o comprovante.' \
      --form medias=@comprovante.pdf
    ```
  </Tab>

  <Tab title="template">
    Obrigatório para iniciar uma conversa fora da janela de atendimento do WhatsApp. Os templates
    aprovados do canal estão em `GET /channels/{id}/templates`.

    ```json theme={null}
    {
      "channelId": 4,
      "type": "template",
      "number": "5511999999999",
      "template": {
        "name": "confirmacao_pedido",
        "parameters": ["Marina", "88213"]
      }
    }
    ```

    Recomendamos esta forma. Você informa o nome e os parâmetros, e a API confere com o template
    aprovado e monta a mensagem. Se você já monta o objeto com `components`, pode continuar
    enviando desse jeito.
  </Tab>

  <Tab title="interactive">
    Envia o objeto `interactive` da API oficial do WhatsApp: botões de resposta (`button`), lista
    (`list`), botão de link (`cta_url`), pedido de localização (`location_request_message`) e
    carrossel (`carousel`), conforme o que o canal suporta.

    ```json theme={null}
    {
      "channelId": 4,
      "type": "interactive",
      "number": "5511999999999",
      "interactive": {
        "type": "button",
        "body": { "text": "Podemos confirmar sua entrega para amanhã?" },
        "action": {
          "buttons": [
            { "type": "reply", "reply": { "id": "sim", "title": "Sim" } },
            { "type": "reply", "reply": { "id": "nao", "title": "Reagendar" } }
          ]
        }
      }
    }
    ```

    No **Webchat**, os cinco tipos acima aparecem no chat do visitante como no WhatsApp, e o
    `interactive` é conferido na própria chamada, com os limites do WhatsApp: um problema responde
    `422 ERR_API_INTERACTIVE_INVALID` na hora, com o campo e o motivo. Veja
    [Webchat](/guides/webchat#mensagens-interativas).
  </Tab>
</Tabs>

## Para quem enviar

Há três formas de indicar o destinatário. Se vier mais de uma, vale nesta ordem: `ticketId`,
`contactId`, `number`.

<Columns cols={3}>
  <Card title="ticketId" icon="message-square">
    Envia dentro de um atendimento que já existe, e a mensagem fica no mesmo histórico da conversa.
    Use para responder uma conversa em andamento.
  </Card>

  <Card title="contactId" icon="user">
    Envia para um contato que já existe, em qualquer canal. É obrigatório nos canais sem telefone
    (Instagram, Facebook/Messenger, Webchat, Telegram): neles só dá para enviar a quem já conversou
    com o canal. No Webchat, o visitante precisa ter aberto o webchat deste canal.
  </Card>

  <Card title="number" icon="phone">
    Número do destinatário, em canais de telefone. Se o contato ainda não existir, ele é criado, e
    você pode usar `contactName` para dar um nome a ele. Se não houver atendimento aberto com esse
    contato, um novo é aberto.
  </Card>
</Columns>

## Controlando o atendimento no mesmo envio

Quatro campos opcionais mudam o atendimento na mesma chamada do envio, sem precisar de uma segunda
requisição:

<ParamField body="queueId" type="integer">
  Move o atendimento para esta fila depois do envio.
</ParamField>

<ParamField body="openTicket" type="boolean">
  Reabre o atendimento se ele estiver encerrado.
</ParamField>

<ParamField body="closeTicket" type="boolean">
  Encerra o atendimento depois do envio. Serve para avisos que não esperam resposta.
</ParamField>

<ParamField body="wrapupTypeId" type="integer">
  Qualificação registrada no encerramento do atendimento. Use junto com `closeTicket`.
</ParamField>

## Volume alto

<Warning>
  Não chame `POST /messages` repetidamente para fazer disparos em massa. Cada chamada consome o
  [limite por minuto](/essentials/limites-de-uso) da empresa inteira, e o controle de ritmo, as
  novas tentativas e o relatório ficam por sua conta.

  Para isso existe o módulo de **campanhas**. Ele controla o ritmo de saída, permite pausar,
  retomar e cancelar o envio, e mostra um relatório de entrega no final.
</Warning>

<CardGroup cols={2}>
  <Card title="Idempotência" icon="repeat" href="/essentials/idempotencia">
    Como evitar que uma nova tentativa duplique a mensagem.
  </Card>

  <Card title="Referência de mensagens" icon="code" href="/api-reference/introduction">
    Todos os campos aceitos, com playground para testar.
  </Card>
</CardGroup>


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