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

# Enviar mensagem

> Envia uma comunicação cadastrada no painel para um destinatário (envio único) ou para até 100 destinatários (lote, campo `messages`). Sem `channels`, a mensagem sai em todos os canais ativos da comunicação, com a versão publicada de cada template (rascunhos do editor não saem pela API). Cada mensagem consome 1 do limite por minuto da conta (60 por padrão); o excedente é adiado e enviado nos minutos seguintes. Se a conta tiver um limite diário de mensagens, cada envio a um canal conta 1; acima dele, o canal volta `failed` com `error_code: "daily_limit_reached"`. Por padrão o envio pela API é transacional e não é bloqueado pelo descadastro do contato; com `respect_opt_out: true`, o canal (e-mail, WhatsApp ou SMS) de que o contato se descadastrou é pulado e volta `skipped` com `reason_code: "contato_descadastrado"`.



## OpenAPI

````yaml openapi.json POST /send-message
openapi: 3.1.0
info:
  title: OctaSend API
  description: >-
    API de mensageria multicanal — envie mensagens por E-mail, WhatsApp, SMS,
    Slack, Telegram, Web Push, In-App e Push mobile através de um único
    endpoint.
  version: 1.3.0
servers:
  - url: https://yghpblhxrfmxkwejvpjz.supabase.co/functions/v1
    description: Produção
security:
  - bearerAuth: []
tags:
  - name: Autenticação
  - name: Mensagens
  - name: Automações
  - name: Consultas
  - name: Widget In-App
  - name: Web Push
paths:
  /send-message:
    post:
      tags:
        - Mensagens
      summary: Enviar mensagem
      description: >-
        Envia uma comunicação cadastrada no painel para um destinatário (envio
        único) ou para até 100 destinatários (lote, campo `messages`). Sem
        `channels`, a mensagem sai em todos os canais ativos da comunicação, com
        a versão publicada de cada template (rascunhos do editor não saem pela
        API). Cada mensagem consome 1 do limite por minuto da conta (60 por
        padrão); o excedente é adiado e enviado nos minutos seguintes. Se a
        conta tiver um limite diário de mensagens, cada envio a um canal conta
        1; acima dele, o canal volta `failed` com `error_code:
        "daily_limit_reached"`. Por padrão o envio pela API é transacional e não
        é bloqueado pelo descadastro do contato; com `respect_opt_out: true`, o
        canal (e-mail, WhatsApp ou SMS) de que o contato se descadastrou é
        pulado e volta `skipped` com `reason_code: "contato_descadastrado"`.
      operationId: sendMessage
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/SendMessageRequest'
                - $ref: '#/components/schemas/SendMessageBatchRequest'
            examples:
              single:
                summary: Mensagem única
                value:
                  communication_slug: boas-vindas
                  recipient:
                    email: usuario@exemplo.com
                    phone: '+5511999990000'
                  variables:
                    nome: Ricardo
                  language: pt-BR
                  tag:
                    - onboarding
                    - junho-2024
              batch:
                summary: Lote (até 100 mensagens)
                value:
                  messages:
                    - communication_slug: boas-vindas
                      recipient:
                        email: joao@exemplo.com
                      variables:
                        nome: João
                    - communication_slug: boas-vindas
                      recipient:
                        email: maria@exemplo.com
                      variables:
                        nome: Maria
      responses:
        '200':
          description: >-
            Requisição aceita. O HTTP 200 não garante entrega: confira
            `results[].status` de cada canal. Quando o limite por minuto é
            atingido, o envio único volta com `deferred: true` e `status:
            "queued"`, sem `results`. Quando o limite diário da conta é
            atingido, o canal volta `failed` com `error_code:
            "daily_limit_reached"`, também com HTTP 200.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SendMessageResponse'
                  - $ref: '#/components/schemas/SendMessageDeferredResponse'
                  - $ref: '#/components/schemas/SendMessageBatchResponse'
              examples:
                single:
                  summary: Envio único
                  value:
                    success: true
                    results:
                      - channel: email
                        status: sent
                        provider_message_id: 010f018e...
                        log_id: 3f1c2b9e-...
                      - channel: whatsapp
                        status: skipped
                        error: Canal não configurado
                        reason_code: channel_not_configured
                opted_out:
                  summary: 'Canal pulado por descadastro (com respect_opt_out: true)'
                  value:
                    success: true
                    results:
                      - channel: email
                        status: skipped
                        error: Contato descadastrado
                        reason_code: contato_descadastrado
                        log_id: 7c1e0a52-...
                daily_limit:
                  summary: Canal recusado pelo limite diário da conta
                  value:
                    success: true
                    results:
                      - channel: email
                        status: failed
                        error: Limite diário de mensagens atingido
                        error_code: daily_limit_reached
                        log_id: 5b0e7a13-...
                deferred:
                  summary: Envio único adiado pelo limite por minuto
                  value:
                    success: true
                    deferred: true
                    status: queued
                batch:
                  summary: Lote
                  value:
                    success: true
                    batch: true
                    total: 3
                    deferred: 1
                    results:
                      - communication_slug: boas-vindas
                        results:
                          - channel: email
                            status: sent
                            log_id: 3f1c2b9e-...
                      - communication_slug: boas-vindas-antiga
                        error: Communication not found
                      - communication_slug: boas-vindas
                        status: queued
                        deferred: true
        '400':
          description: Payload inválido
          content:
            application/json:
              examples:
                missing_slug:
                  value:
                    error: communication_slug is required
                empty_batch:
                  value:
                    error: messages array cannot be empty
                batch_too_large:
                  value:
                    error: Maximum 100 messages per batch request
                batch_missing_slug:
                  value:
                    error: Each message must have communication_slug
                invalid_respect_opt_out:
                  value:
                    error: respect_opt_out must be a boolean
                batch_invalid_respect_opt_out:
                  value:
                    error: respect_opt_out must be a boolean in each message
        '401':
          description: Credencial ausente, inválida, expirada ou revogada
          content:
            application/json:
              examples:
                missing:
                  value:
                    error: >-
                      Authorization header required. Use: Authorization: Bearer
                      <token>
                invalid:
                  value:
                    error: Invalid, expired or revoked token
        '404':
          description: >-
            Envio único: comunicação inexistente ou inativa. No lote, o mesmo
            caso volta como item com `error`, sem recusar a requisição.
          content:
            application/json:
              example:
                error: Communication not found
        '500':
          description: Erro interno (inclusive corpo JSON malformado)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            Envio único com `respect_opt_out: true` em que a consulta ao
            descadastro falhou. Nada foi enviado; reenvie a mensagem. No lote, o
            mesmo caso volta só no item afetado, com `error` e `error_code`, sem
            recusar a requisição.
          content:
            application/json:
              example:
                error: >-
                  Não foi possível verificar o descadastro do contato. Nada foi
                  enviado; tente de novo.
                error_code: opt_out_check_failed
components:
  schemas:
    SendMessageRequest:
      type: object
      required:
        - communication_slug
      properties:
        communication_slug:
          type: string
          description: Slug de uma comunicação ativa da conta
        recipient:
          $ref: '#/components/schemas/Recipient'
        variables:
          type: object
          description: Valores (texto) das `{{variáveis}}` do template
          additionalProperties:
            type: string
        language:
          type: string
          example: pt-BR
          description: >-
            Idioma preferido. Ordem de escolha do template: este idioma, a base
            dele (pt), o idioma padrão da conta, o de fallback e `en`. Se nenhum
            casar e o canal tiver um único template ativo, ele é usado; senão, o
            canal volta `skipped` com `No template found for any language`
        channels:
          type: array
          description: >-
            Restringe o envio a estes canais. Um canal pedido que não está ativo
            na comunicação é ignorado. Sem ele, a mensagem sai em todos os
            canais ativos da comunicação
          items:
            $ref: '#/components/schemas/Channel'
        tag:
          description: >-
            Uma ou mais tags para agrupar os envios e filtrar depois em
            `/query-message-logs`. Espaços nas pontas são removidos e tags
            vazias, descartadas
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        respect_opt_out:
          type: boolean
          default: false
          description: >-
            Com `true`, o canal (`email`, `whatsapp` ou `sms`) de que o contato
            se descadastrou é pulado e volta `skipped` com `reason_code:
            "contato_descadastrado"`; os outros canais seguem. O contato é
            reconhecido pelo `recipient.email` (sem diferenciar maiúsculas) e
            pelo `recipient.phone`. Os e-mails pela API não levam o link de
            descadastro, nem com `true`. Um valor que não seja `true` nem
            `false` é recusado com 400
    SendMessageBatchRequest:
      type: object
      required:
        - messages
      properties:
        messages:
          type: array
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/SendMessageRequest'
    SendMessageResponse:
      type: object
      properties:
        success:
          type: boolean
        results:
          type: array
          items:
            $ref: '#/components/schemas/ChannelResult'
    SendMessageDeferredResponse:
      type: object
      description: Envio único adiado pelo limite por minuto da conta
      properties:
        success:
          type: boolean
          const: true
        deferred:
          type: boolean
          const: true
        status:
          type: string
          const: queued
    SendMessageBatchResponse:
      type: object
      properties:
        success:
          type: boolean
        batch:
          type: boolean
          const: true
        total:
          type: integer
          description: Quantidade de itens recebidos
        deferred:
          type: integer
          description: Quantos itens foram adiados pelo limite por minuto
        results:
          type: array
          description: Um item por mensagem. Os adiados vêm no fim.
          items:
            type: object
            properties:
              communication_slug:
                type: string
              results:
                type: array
                items:
                  $ref: '#/components/schemas/ChannelResult'
              error:
                type: string
                description: >-
                  Ex.: `Communication not found`, ou a falha ao consultar o
                  descadastro com `respect_opt_out: true` (nada foi enviado para
                  o item)
              error_code:
                type: string
                description: >-
                  Presente quando a consulta ao descadastro falhou:
                  `opt_out_check_failed`. Reenvie só esse item
                example: opt_out_check_failed
              status:
                type: string
                const: queued
                description: Presente quando o item foi adiado
              deferred:
                type: boolean
    Error:
      type: object
      properties:
        error:
          type: string
    Recipient:
      type: object
      description: >-
        Informe os campos dos canais que vão ser usados. Sem `channels`, um
        canal para o qual o destinatário não tem dado é pulado sem gerar
        registro; com `channels`, ele volta em `results` como `skipped`, com o
        campo que faltou em `error`. Exceção: o Slack sem canal padrão nem
        Incoming Webhook, para destinatário sem `slack_channel`, `slack_user_id`
        e `email`, é pulado sem registro nos dois casos.
      properties:
        email:
          type: string
          format: email
          description: >-
            E-mail. Canal `email`; no Slack, abre mensagem direta com o dono do
            e-mail (exige Bot Token)
        phone:
          type: string
          example: '+5511999990000'
          description: >-
            Telefone no formato internacional, com `+` e código do país (ex.:
            +5511999990000). Canais `whatsapp` (só celular brasileiro) e `sms`
            (vai ao provedor como enviado). No WhatsApp, no cadastro do contato
            e na conferência do descadastro, um número sem `+` é lido assim: 10
            dígitos, fixo brasileiro, e 11 dígitos com 9 na terceira posição,
            celular brasileiro (os dois recebem o 55); os demais, com 11 dígitos
            ou mais, já trazem o código do país
        user_id:
          type: string
          description: >-
            Identificador do usuário no seu sistema — o mesmo usado no registro
            do Web Push, no widget In-App ou no link de início do bot do
            Telegram. Canais `web_push`, `in_app` e `telegram`
        fcm_token:
          type: string
          description: Token FCM do navegador, para `web_push` sem registro prévio
        telegram_chat_id:
          type: string
          example: '123456789'
          description: >-
            Chat ID de quem vai receber no Telegram. Tem prioridade sobre
            `user_id` e `phone`, que só encontram quem já iniciou o bot (pelo
            link com o `user_id`) ou compartilhou o número com ele; sem esse
            vínculo, o canal volta `failed`
        slack_user_id:
          type: string
          description: ID do usuário no Slack, para mensagem direta
        slack_channel:
          type: string
          example: '#geral'
          description: Canal do Slack (nome ou ID)
        push_token:
          type: string
          description: >-
            Endpoint do dispositivo no Amazon SNS, para o canal `push` (Push
            mobile)
    Channel:
      type: string
      enum:
        - email
        - whatsapp
        - sms
        - telegram
        - slack
        - web_push
        - in_app
        - push
    ChannelResult:
      type: object
      properties:
        channel:
          $ref: '#/components/schemas/Channel'
        status:
          type: string
          enum:
            - sent
            - queued
            - failed
            - skipped
        provider_message_id:
          type: string
        error:
          type: string
          description: Motivo, quando o status é `failed` ou `skipped`
        error_code:
          type: string
          description: >-
            Código fixo do motivo, para não depender do texto de `error`. Hoje
            só `daily_limit_reached` (limite diário de mensagens da conta
            atingido)
          example: daily_limit_reached
        reason_code:
          type: string
          description: >-
            Código fixo do motivo de um canal `skipped`:
            `channel_not_configured` (o canal não está configurado na conta; o
            envio nem começa) ou `contato_descadastrado` (com `respect_opt_out:
            true`, o contato se descadastrou do canal)
          example: contato_descadastrado
        log_id:
          type:
            - string
            - 'null'
          format: uuid
          description: >-
            Identificador do registro no histórico (o mesmo `id` de
            `/query-message-logs`). Ausente quando o canal foi pulado antes de
            gerar registro, como em `channel_not_configured`
        note:
          type: string
          description: Só no WhatsApp enfileirado
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Access token (`at_...`) obtido em `/oauth-token`, ou o par
        `client_id:client_secret` separado por dois-pontos, sem espaços.

````

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