Skip to main content
O endpoint POST /send-message dispara uma comunicação cadastrada no painel para um destinatário — em todos os canais ativos dela ou só nos que você escolher. O conteúdo de cada canal vem da versão publicada do template da comunicação; a sua integração só informa quem recebe e os valores das variáveis. Antes de começar, obtenha um access token em Autenticação.
O channels do exemplo restringe o envio a esses quatro canais, cada um com o dado de recipient que ele usa: e-mail (email), WhatsApp (phone), Web Push e In-App (user_id). Sem channels, a mensagem sai em todos os canais ativos da comunicação para os quais o recipient tem dado.

Parâmetros do body

Campos do destinatário

Canais disponíveis

Todo canal, exceto In-App, precisa estar configurado em Configurações → Canais. Sem configuração, o envio por aquele canal nem começa: o resultado volta como skipped, com o erro Canal não configurado e reason_code: "channel_not_configured", sem log_id e sem registro em Logs. Os outros canais da comunicação seguem normalmente. O In-App não tem configuração, mas respeita a chave Canal habilitado da página do canal: desligada, o resultado volta como skipped com o erro Canal in-app desabilitado. Veja os guias de WhatsApp, E-mail, Web Push, Slack e Telegram.

Regras de envio

Quais canais recebem

  • A comunicação é procurada pelo communication_slug entre as comunicações ativas da conta. Se não existir ou estiver inativa, a resposta é 404 Communication not found. Se você desativar a comunicação no painel, as chamadas com o slug dela passam a receber esse 404; se trocar o slug, as chamadas com o slug antigo também.
  • Sem channels, o envio sai em todos os canais ativos da comunicação. Com channels, só nos canais que estão na lista e ativos na comunicação — um canal pedido que a comunicação não tem ativo é ignorado.
  • Destinatário sem os dados de um canal:
    • sem channels, o canal é pulado em silêncio — não aparece em results nem nos logs. Assim uma comunicação multicanal pode ser enviada a quem só tem e-mail, por exemplo;
    • com channels, o canal aparece em results com status skipped e um error que diz qual campo faltou — exceto o Slack: se o canal Slack não tiver canal padrão nem Incoming Webhook e o destinatário vier sem slack_channel, slack_user_id e email, ele é pulado em silêncio mesmo quando pedido em channels.
Se nenhum canal tiver dados do destinatário e você não informou channels, a resposta volta com results vazio: nada foi enviado nem registrado.

Versão publicada do template

O envio usa sempre a versão publicada de cada template. No editor do painel, o que você grava com Salvar rascunho não sai pela API até você clicar em Publicar. Uma versão de idioma que ainda não foi publicada não entra na escolha do idioma. O Enviar teste do editor é o único envio que usa o rascunho.

Idioma do template

Cada canal da comunicação pode ter um template por idioma. A plataforma escolhe o primeiro que existir nesta ordem:
  1. o idioma enviado em language (ex.: pt-BR);
  2. a base desse idioma (ex.: pt);
  3. o Idioma padrão da conta;
  4. o Idioma de fallback da conta;
  5. en.
Se nenhum casar e o canal tiver um único template ativo, ele é usado mesmo assim. Com dois ou mais templates e nenhum casando, o canal fica skipped com o erro No template found for any language — a plataforma não escolhe um idioma ao acaso. O idioma padrão e o de fallback ficam em Configurações.

Variáveis

  • Use {{nome_da_variavel}} no template. Nomes com ponto também funcionam (ex.: {{pedido.numero}}).
  • Variável que o template usa mas não veio em variables fica no texto como está (ex.: {{nome}}) — confira os nomes antes de enviar.
  • No corpo HTML do e-mail, o valor das variáveis é tratado como texto: HTML enviado dentro de uma variável aparece como texto, e quebras de linha viram quebras de linha no e-mail.
  • No WhatsApp e no SMS, o texto final (template com as variáveis já preenchidas) acima de 3.800 caracteres é cortado e termina com […continua].

Telefone

Envie recipient.phone sempre com + e o código do país (ex.: +5511999990000). Um número sem o + é lido assim no WhatsApp, no cadastro do contato e na conferência do descadastro: No SMS, o número vai ao provedor como você enviou: use o formato internacional.

Contatos

Os envios para um destinatário com e-mail ou telefone criam ou atualizam o contato correspondente em Contatos. Quando recipient.email é enviado, o nome do contato é preenchido com o valor da variável nome (ou name), se ela vier no envio, e o telefone, com recipient.phone na regra da seção Telefone. Um contato removido no painel não volta por causa de um envio: ele continua removido.

Resposta

HTTP 200 significa que a requisição foi aceita, não que a mensagem foi entregue. Confira o status de cada item de results. O que acontece depois do envio (entrega, leitura, clique, recusa do provedor) aparece em Logs e em Consultar logs — ou chega até você por Webhook de status.

Envio em lote

Envie de 1 a 100 mensagens numa única chamada com o campo messages. Cada item aceita os mesmos campos do envio único (communication_slug, recipient, variables, language, channels, tag, respect_opt_out, external_id) e pode usar uma comunicação diferente.
Sem channels, o item sai em todos os canais ativos da comunicação para os quais o recipient tem dado.

Exemplos por canal

Um item para cada canal, com o recipient que ele exige (veja Canais disponíveis). Os itens podem ser misturados no mesmo lote. Os exemplos supõem que a comunicação boas-vindas tem todos esses canais configurados; sem a configuração, o item daquele canal volta como skipped.
Regras do lote:
  • Todo item precisa de communication_slug. Se algum não tiver, o lote inteiro é recusado com 400 e nada é enviado. O mesmo vale para um respect_opt_out que não seja true nem false.
  • Um slug inexistente ou inativo não derruba o lote: aquele item volta com "error": "Communication not found" e os demais seguem.
  • Com respect_opt_out: true, uma falha ao consultar o descadastro também fica só no item: ele volta com error e "error_code": "opt_out_check_failed", nada é enviado para ele e os demais seguem. Reenvie só esse item.
  • Para listas maiores que 100, divida em lotes e faça várias chamadas.

Resposta do lote

Limite de envio por minuto

Cada conta tem um orçamento de mensagens por minuto — 60 por padrão. Cada mensagem conta 1, qualquer que seja o número de canais; num lote, cada item conta 1. Para aumentar o limite, fale com a OctaSend. O orçamento é da conta inteira: além das chamadas à API, as mensagens disparadas por automações, recuperação de carrinho e eventos das lojas integradas consomem do mesmo limite. O excedente não é recusado — ele é adiado:
  • Envio único: a resposta é {"success": true, "deferred": true, "status": "queued"}, sem results.
  • Lote: os primeiros itens, até o que cabe no minuto, são processados na hora; os demais são adiados e aparecem no fim de results com status: "queued" e deferred: true.
A resposta adiada não traz message_id (o registro só nasce quando a mensagem é reprocessada) e devolve o external_id enviado. As mensagens adiadas saem nos minutos seguintes, conforme o orçamento libera, e o resultado de cada canal aparece em Logs — exceto os canais pulados por falta de dado do destinatário, que não geram registro, como no envio imediato. Use tag para encontrá-las depois em Consultar logs. Uma mensagem adiada que não consegue sair em cerca de 24 horas é descartada.
O adiamento acontece antes de a comunicação ser conferida: a resposta queued não valida o communication_slug. Se a comunicação não existir ou estiver inativa quando a mensagem sair da fila, ela é descartada sem registro em Logs. Confira o slug antes de disparar volumes grandes — por exemplo, com um envio que não seja adiado, que responde 404 Communication not found quando a comunicação não existe.

Limite diário da conta

Se a conta tiver um Limite diário de mensagens em Configurações, cada envio a um canal conta 1: uma mensagem que sai por e-mail e WhatsApp conta 2. O dia vira à meia-noite, no fuso horário da conta; se o fuso da conta for inválido, vale o de America/Sao_Paulo. Com o campo vazio, não há limite. O limite vale para a conta inteira: envios pela API (único e lote), campanhas, automações, eventos das lojas integradas, mensagens adiadas pelo limite por minuto e o Enviar teste do painel. Respostas do chatbot ou do atendente nas conversas não contam. Mensagens da plataforma, como o código de acesso ao painel, os convites de usuário, as boas-vindas e os alertas do Token Control, também não contam nem são recusadas pelo limite. Acima do limite, o canal não é chamado. A resposta continua HTTP 200 e o canal volta assim — no lote, dentro do item:
  • O envio recusado fica em Logs com status Falhou e esse motivo.
  • Canais pulados antes do envio (por falta de dado do destinatário, sem template, sem configuração ou por descadastro) não contam.
  • Aumentar o limite no mesmo dia libera o saldo novo na hora.
  • Os envios do dia são contados mesmo sem limite. Se você definir o limite no meio do dia, os envios que já saíram hoje entram na conta.
  • Em Configurações, o painel mostra quanto já foi usado no dia e avisa quando o limite é atingido.
  • Campanhas não viram uma fila de falhas: quando a conta atinge o limite no meio do envio, a campanha fica Pausada e volta a enviar sozinha à meia-noite, no fuso da conta. Veja Campanhas.

Descadastro de contatos

O contato pode se descadastrar por canal (e-mail, WhatsApp e SMS). O descadastro vale para as mensagens de marketing. As mensagens transacionais, sobre um pedido ou a conta do próprio contato, continuam chegando. Quando o descadastro é respeitado, o canal descadastrado não é enviado e fica em Logs com o status skipped e o motivo Contato descadastrado. Os outros canais da mesma mensagem seguem normalmente. Os e-mails de campanha e de automação de marketing levam no rodapé o link de descadastro.

Respeitar o descadastro pela API

Envie respect_opt_out: true no corpo do send-message (no lote, em cada item de messages). O contato é reconhecido pelo recipient.email, sem diferenciar maiúsculas, e pelo recipient.phone. O canal descadastrado volta assim:
  • Use reason_code para identificar o pulo sem depender do texto de error.
  • Telegram, Slack, Web Push, In-App e Push mobile não têm descadastro e não são afetados.
  • O campo vale também para mensagens adiadas pelo limite por minuto.
  • Se a consulta ao descadastro falhar, nada é enviado para aquela mensagem e a resposta traz "error_code": "opt_out_check_failed": no envio único, com HTTP 503; no lote, só no item afetado, e os outros itens seguem. Reenvie a mensagem.
Os e-mails enviados pela API não levam o link de descadastro, nem com respect_opt_out: true. Se você usa a API para comunicação de marketing, oferecer o descadastro é responsabilidade do seu sistema: não chame o send-message para quem pediu para sair, ou envie respect_opt_out: true para a OctaSend pular os canais de que o contato se descadastrou. Veja o descadastro de cada contato em Contatos.

WhatsApp

Número do destinatário

  • O envio de WhatsApp pela API aceita somente celular brasileiro: DDI 55, DDD e número de 9 dígitos começando por 6, 7, 8 ou 9. Número fixo ou de outro país volta como failed com o erro Invalid phone number.
  • Informe o número com +55 (ex.: +5511999990000). Um celular de 11 dígitos sem DDI, com DDD e o 9 na frente do número, com ou sem máscara (ex.: (11) 99999-0000), recebe o 55 automaticamente. Veja Telefone.
  • Número que não está registrado no WhatsApp volta como skipped com o erro Número não está registrado no WhatsApp.

Método de envio

O método de envio (Meta Cloud API ou Evolution API) é definido na conexão do canal dentro da plataforma — a integração pela API não precisa especificá-lo. Veja o guia de WhatsApp. Pela Evolution API com a fila ligada, a mensagem entra numa fila e sai em intervalos: o resultado imediato é queued, e o resultado final aparece em Logs.
  • A fila respeita o Intervalo mínimo entre envios da conta, em Configurações → Canais → WhatsApp → Configurações Gerais: de 1 a 60 segundos entre uma mensagem e a próxima. Em branco, a fila segue só o limite por minuto. O intervalo de uma conta não atrasa a fila das outras. Ao mudar o intervalo, as mensagens que já esperam na fila passam a seguir o ritmo novo.
  • Quando o envio falha por um problema passageiro, como o número desconectado, a fila tenta de novo até o máximo de tentativas da conta. Sem novas tentativas configuradas, a primeira falha é final.
  • Depois que a mensagem sai, o registro em Logs passa para Entregue e Lida conforme o WhatsApp confirma. Veja Consultar logs.

Sequência de mensagens

O template de WhatsApp pode ter uma sequência de mensagens, com uma espera configurável depois de cada uma (padrão: 1 segundo). A resposta traz um único resultado para o canal: failed se algum item falhou; senão queued se algum foi para a fila; senão skipped se nenhum item saiu porque o número não tem WhatsApp; senão sent. Cada pausa entre mensagens enviadas na hora é limitada a 30 segundos, e a soma das pausas de uma sequência, a 60 segundos — depois disso, os itens restantes seguem sem pausa.

Mensagens ricas

Botões, listas, mídia, áudio e carrossel são configurados no template da comunicação, pelo editor do painel — o payload da API não muda: continue enviando communication_slug, recipient.phone e variables. As {{variáveis}} funcionam em todos os campos de texto do conteúdo rico (legendas, títulos, textos de botões e itens de lista).
Botões e listas dependem do aparelho do destinatário. Se o envio de botões ou lista falhar, a plataforma reenvia automaticamente como texto com as opções numeradas.
No método Meta (Cloud API oficial), uma mensagem de texto simples, sozinha, usa o template aprovado configurado na conexão (campo Template Name), se houver um. Nesse caso:
  • o destinatário recebe o texto do template aprovado na Meta, não o texto do template da comunicação;
  • o idioma é o do campo Template Language da conexão (pt_BR quando vazio);
  • os valores de variables preenchem os parâmetros {{1}}, {{2}}… do template aprovado na ordem numérica das chaves — use "1", "2"… como nomes. Chaves não numéricas entram depois, em ordem alfabética. Todas as chaves enviadas em variables viram parâmetros, então envie só as que o template aprovado usa;
  • o envio pode sair fora da janela de 24 horas.
Sem template aprovado configurado na conexão, o texto vai como mensagem livre. Conteúdo rico ou sequência com mais de uma mensagem também é enviado como mensagem livre. Mensagem livre só é entregue dentro da janela de 24 horas de atendimento (o destinatário precisa ter enviado uma mensagem recentemente). Fora da janela, a Meta rejeita o envio e o erro fica registrado no log. Diferenças do método Meta em relação à Evolution:

In-App

O canal In-App não tem configuração de credenciais: a notificação é gravada para o recipient.user_id e aparece no widget instalado no seu produto. Veja Widget In-App.

Disparar uma automação pela API

Se a sua conta usa Automações — módulo opcional, fale com a OctaSend para ativar —, um fluxo cujo início é Chamada de API pode ser disparado pelo endpoint POST /flow-trigger, com a mesma autenticação:
  • trigger_slug é o Identificador do gatilho definido no início do fluxo. Só fluxos ativos são disparados.
  • recipient precisa de ao menos um identificador: email, phone, user_id, telegram_chat_id, slack_user_id, slack_channel ou fcm_token.
  • idempotency_key é opcional. Chamadas repetidas com a mesma chave para o mesmo gatilho não iniciam uma nova execução — elas voltam contadas em duplicated. Sem a chave, cada chamada inicia uma execução nova.
  • A resposta informa quantas execuções começaram e quantas foram ignoradas por repetição, ex.: {"started": 1, "duplicated": 0}. Mais de um fluxo ativo pode usar o mesmo identificador. Se nenhum fluxo ativo usa o trigger_slug, a resposta é 404.
  • Cada chamada consome 1 do limite por minuto. Aqui o excedente não é adiado: a resposta é 429 com {"error": "rate_limited", "retry_after": 60}.
  • As mensagens dessas automações são tratadas como marketing: o canal de que o contato se descadastrou é pulado, e o e-mail leva o link de descadastro no rodapé. Para uma mensagem transacional, use o send-message. Veja Descadastro de contatos.

Erros

Erros que recusam a requisição inteira: Erros por canal, que chegam em results[].error com HTTP 200:

Exemplos por linguagem