Pular para o conteúdo

Envio de mensagens

Envie mensagens pelo Turbo Notify e siga as políticas do WhatsApp (abre em nova aba) .

O corpo de POST /v1/numbers/{ref}/messages (ou o atalho POST /v1/messages para o número principal) leva o conteúdo da mensagem no objeto content. O tipo vem do campo âncora presente em content (text, image_url, latitude, start_at, …). Não envie um campo content_type na requisição: ele nunca é aceito (incluí-lo retorna 422). Suporta texto, localização, contato, calendário, mensagem com botão de link (interactive_type) e mídia (image, video, audio, document, sticker, veja Envio de mídia).

Para citar (responder) uma mensagem existente (qualquer variante de conteúdo), use o endpoint dedicado POST /v1/messages/{message_id}/reply, onde {message_id} é o id público da mensagem citada (msg_{hex32}). O corpo dessa requisição contém apenas content. O webhook resultante é message.replied (em vez de message.sent); veja Webhooks.

Use a citação para trazer ao contexto uma mensagem anterior, quando a conversa já andou e a sua resposta depende dela (do contato, sua ou, em grupo, de qualquer participante). Para responder à mensagem que acabou de chegar, envie uma mensagem normal, como se faz numa conversa: o chat já mostra o que veio antes, e uma citação em toda resposta só polui.

Dá para responder a qualquer mensagem dos últimos 12 meses, inclusive uma cujo conteúdo já expirou (Retenção das mensagens): a conversa continua encadeada pela mensagem citada, só que o balão de citação vai sem o texto original.

Antes de enviar (ou de responder), o Turbo Notify abre a conversa como uma pessoa faria: o número aparece online, o histórico de mensagens não lidas do chat de destino é marcado como lido e só então a mensagem é enviada. Para marcar um chat como lido sem enviar nenhuma mensagem, veja Marcar como lida.

Envio básico

O envio básico leva só o número do destinatário e o texto. O remetente é o número principal da sua conta.

turbo-notify.sh
curl -X POST \
https://api.turbonotify.com/v1/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"to": {"number": "+5511988887777"},
"content": {
"text": "Olá, esta é uma mensagem enviada pelo Turbo Notify!"
}
}'

Depois do envio, o texto pode ser corrigido com Editar mensagem.

Menções (@mentions)

Para mencionar alguém, escreva o token @<numero> no text (ou no caption de mídia, veja Envio de mídia): @ seguido do telefone do contato em dígitos E.164, sem +. É uma menção real do WhatsApp, com nome tocável e notificação no aparelho de quem foi mencionado.

POST /v1/messages: texto com menção (1:1)
{
"to": { "number": "+5511988887777" },
"content": {
"text": "Olá @5511977776666, seu pedido chegou!"
}
}

Em grupos, mencione um participante pelo número:

POST /v1/messages: grupo mencionando um participante
{
"to": { "group_id": "grp_e442553a56b14e2695f6acfd7d651b1a" },
"content": {
"text": "Bom dia @5511977776666, pode validar o pedido de hoje?"
}
}

A requisição não tem campo mentions: o Turbo Notify detecta as menções no próprio texto. Todo token válido vira uma menção real no dispositivo do destinatário.

Regras do token

RegraComportamento
Sintaxe@ + 7 a 15 dígitos, delimitado por fronteira de palavra: nome@dominio.com, @@123, sequências com mais de 15 dígitos e @+55… não viram menção
NormalizaçãoNúmeros BR de 12 dígitos são normalizados para a forma de 13 dígitos: o conteúdo guardado e devolvido traz o token normalizado (ex.: @551177776666 → @5511977776666)
Token inválidoDígitos inválidos ou não normalizáveis ficam como texto comum: o envio nunca falha por causa de uma menção
Onde funcionaEm 1:1 e em grupos, em text e em caption de image/video/document (audio/sticker não têm legenda)
Reuso do token recebidoO token @<numero> que você recebe em message.received pode ser colado de volta no envio: a menção funciona sem nenhuma conversão
CotaMencionar alguém nunca consome cota de mensagens nem de contatos

Depois do envio, a mensagem passa a carregar a estrutura mentions (lista de {contact_id?, name?, number}: contact_id e name são omitidos quando a menção não corresponde a um contato conhecido) em GET /v1/messages/{message_id} e no data.mentions dos eventos message.sent/message.replied/message.edited. Um @<digitos> literal no texto só é menção se constar dessa estrutura.

As mesmas regras de detecção valem para POST .../messages/{message_id}/reply (o text/caption da resposta) e para POST .../messages/{message_id}/edit (o novo text ou caption da edição substitui todo o conjunto de menções da mensagem, veja Editar e apagar mensagens).

Envio com número extra

Para enviar a partir de um número extra cadastrado e ativo na sua conta, use o alias do número diretamente no caminho da URL.

turbo-notify.sh
curl -X POST \
https://api.turbonotify.com/v1/numbers/vendas-sp/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"to": {"number": "+5511988887777"},
"content": {
"text": "Mensagem enviada a partir de um número extra."
}
}'

Se o alias da URL não for de um número extra cadastrado e ativo, o envio é rejeitado.

Saiba mais em Inclusão de números extras.

Envio sem duplicar

O envio (POST .../messages) e a resposta (POST .../messages/{message_id}/reply) aceitam o cabeçalho opcional Idempotency-Key: um texto de até 255 caracteres escolhido por você. Se a requisição falhar por tempo esgotado ou erro de rede e você repetir com a mesma chave, no mesmo número, a mensagem não é enviada de novo: a resposta traz o message_id da mensagem original. Sem a chave, repetir pode entregar a mensagem em dobro.

Use uma chave nova para cada mensagem nova, derivada de algo estável do seu lado (por exemplo o id do pedido que gerou a notificação). Uma chave vazia ou com mais de 255 caracteres é recusada com 400 invalid_idempotency_key.

Terminal window
curl -X POST https://api.turbonotify.com/v1/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-4711-confirmacao" \
-d '{"to": {"number": "+5511988887777"}, "content": {"text": "Seu pedido foi confirmado."}}'

Erros possíveis

StatusCódigo de erroDescrição
400contact_not_foundO contact_id informado não pertence à organização.
400contacts_not_enabledEnvio por contact_id não configurado.
400invalid_phone_numberO to.number informado não é um telefone válido em formato E.164 (ex.: +5511988887777).
400invalid_recipientNão foi possível resolver o destinatário informado em to para um endereço de envio. Informar nenhum ou mais de um entre number, group_id e contact_id retorna 422 validation_error.
400not_group_memberSeu número não é mais participante do group_id informado, veja Envio para grupo.
402feature_not_availableEnvio para grupo (to.group_id) requer plano Empresarial ou superior, veja Envio para grupo.
402subscription_inactiveAssinatura com pagamento pendente, encerrada ou com período de teste expirado (details.status). Bloqueia todo envio até a assinatura voltar a ficar ativa.
402contact_quota_exceededCota de contatos distintos do ciclo atual esgotada, veja Cota e uso.
401not_authenticatedA chave de API está inválida ou ausente.
403insufficient_scopeA chave de API não possui o escopo messages:send (resposta inclui required_scope).
404number_not_foundO alias ou o id informado na URL não corresponde a nenhum número cadastrado na conta.
400invalid_number_idO valor na URL começa com num_, mas não é um id de número válido.
404group_not_foundO group_id informado em to não foi encontrado na conta.
409number_not_connectedO número que envia não está conectado ao WhatsApp. Reconecte o número e tente de novo.
422validation_errorO corpo da requisição está malformado ou não passou na validação. A resposta traz details.errors com os campos rejeitados.
422group_not_owned_by_numberO group_id informado pertence a outro número da conta, não ao alias do caminho da URL.
422message_not_replyable(apenas POST .../messages/{message_id}/reply) A mensagem citada ainda não foi enviada ao WhatsApp ou já foi apagada.
429messages_quota_exceededCota de mensagens do ciclo atual esgotada, veja Cota e uso.
429send_rate_spacingEnvio antes do intervalo mínimo entre mensagens do seu plano, veja Limites de velocidade.
429rate_limit_exceededLimite de requisições por segundo da API ultrapassado. Os demais limites de proteção do envio (messages_per_minute_limit_exceeded, recipients_per_day_limit_exceeded, warmup_limit_exceeded, duplicate_burst_blocked, reply_ratio_too_low) têm códigos próprios, veja Limites de velocidade.
500internal_errorErro interno inesperado no servidor.

Status da mensagem

O status mostra em que etapa a mensagem está. Cada valor é explicado em Status.

Status HTTP: 202
{
  "message_id": "msg_01993c5a1b24d3e9f01a2b3c4d5e6f70",
  "status": {
    "state": "pending",
    "at": "2025-07-16T10:00:00Z",
    "error": null
  }
}

O retorno final do processamento chega via webhook com os eventos message.sent, message.delivered, message.read ou message.send.failed.

Segurança e privacidade

Toda comunicação entre o seu sistema e a API do Turbo Notify usa HTTPS, então os dados trafegam criptografados.

O tempo que o conteúdo das mensagens fica guardado (as mensagens em si ficam disponíveis por 12 meses) está em Retenção das mensagens.


POST /v1/messages aceita quatro variantes de conteúdo rico além de text. Cada variante tem um campo âncora próprio dentro do objeto content e chega ao WhatsApp como o tipo nativo correspondente (locationMessage, contactMessage, eventMessage).

Enviar localização

send-location.sh
curl -X POST \
https://api.turbonotify.com/v1/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"to": {"number": "+5511988887777"},
"content": {
"latitude": -23.5505,
"longitude": -46.6333,
"name": "Avenida Paulista",
"address": "São Paulo, SP",
"url": "https://maps.google.com/?q=-23.5505,-46.6333"
}
}'
CampoTipoObrigatórioValidação
content.latitudenumbersim-90 ≤ x ≤ 90
content.longitudenumbersim-180 ≤ x ≤ 180
content.namestringnãoaté 200 caracteres
content.addressstringnãoaté 500 caracteres
content.urlstringnãoapenas http:///https://

Uma localização enviada não pode ser editada: apagar é a única alteração. Veja o que pode ser alterado depois do envio.

Enviar contato

send-contact.sh
curl -X POST \
https://api.turbonotify.com/v1/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"to": {"number": "+5511988887777"},
"content": {
"display_name": "João Silva",
"phones": [
{ "label": "Mobile", "number": "+5511977776666" },
{ "label": "Work", "number": "+551133334444" }
],
"emails": [
{ "label": "Work", "address": "joao@acme.com" }
],
"organization": "Acme Corp",
"title": "CTO",
"address": "Av. Paulista 1578, São Paulo - SP"
}
}'
CampoTipoObrigatórioNotas
content.display_namestringsim1 a 200 caracteres
content.phones[]arraysim1 a 10 itens; number em E.164
content.phones[].labelstringnãopadrão "Mobile" (Mobile/Home/Work/…)
content.emails[]arraynão0 a 10 itens; address validado como e-mail
content.emails[].labelstringnãopadrão "Email"
content.organizationstringnãoaté 200 caracteres
content.titlestringnãoaté 100 caracteres
content.addressstringnãoaté 500 caracteres

O Turbo Notify monta o cartão de contato (vCard) a partir desses campos. Um cartão enviado não pode ser editado: apagar é a única alteração. Veja o que pode ser alterado depois do envio.

Enviar evento de calendário

send-calendar.sh
curl -X POST \
https://api.turbonotify.com/v1/messages \
-H "Authorization: Bearer SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"to": {"number": "+5511988887777"},
"content": {
"name": "Sprint Planning",
"description": "Planejamento da sprint 24.",
"start_at": "2026-05-01T14:00:00Z",
"end_at": "2026-05-01T15:00:00Z",
"join_link": "https://meet.example.com/abc",
"has_reminder": true,
"reminder_offset_sec": 600,
"location": {
"latitude": -23.5505,
"longitude": -46.6333,
"name": "HQ - Sala Mestre"
}
}
}'
CampoTipoObrigatórioNotas
content.namestringsimtítulo do evento; até 200 caracteres
content.descriptionstringnãoaté 2000 caracteres
content.start_atdatetimesimISO-8601 com timezone (campo âncora da variante calendar)
content.end_atdatetimenãoISO-8601 com timezone; deve ser > start_at
content.join_linkstringnãoapenas http:///https://
content.locationobjectnãomesmo formato do objeto location
content.has_reminderboolnãopadrão false
content.reminder_offset_secintnãosegundos antes do evento; só tem efeito com has_reminder=true e é ignorado, sem erro, quando has_reminder é false ou ausente
content.extra_guests_allowedboolnãopadrão false

Uma mensagem com um botão que abre um link. O campo âncora é interactive_type, sempre "cta_url".

POST /v1/messages: botão com link
{
"to": { "number": "+5511988887777" },
"content": {
"interactive_type": "cta_url",
"body": "Seu pedido foi enviado.",
"footer": "Loja Exemplo",
"url_button": { "display_text": "Rastrear", "url": "https://exemplo.com/rastreio/123" }
}
}
CampoTipoObrigatórioNotas
content.interactive_typestringsimsempre "cta_url"
content.bodystringsim1 a 1024 caracteres
content.headerobjectnão{ "type": "text", "text": "..." }, text com 1 a 60 caracteres
content.footerstringnãoaté 60 caracteres
content.url_button.display_textstringsim1 a 20 caracteres
content.url_button.urlstringsimURL http:// ou https://

Uma mensagem com botão de link não pode ser editada depois de enviada: apagar é a única alteração. Veja o que pode ser alterado depois do envio.

Como aparece no destinatário

Cada tipo aparece no WhatsApp do destinatário com a interface nativa: localização com mapa e botão “Ver no mapa”, contato com cartão que pode ser salvo, calendário com botão “Adicionar ao calendário”, botão com link com o botão logo abaixo do texto.

A entrada que o convidado cria na agenda com o botão “Adicionar ao calendário” não acompanha uma edição ou um cancelamento do evento: veja O que acontece com os convidados.

Para visualizar exatamente como o evento message.sent correspondente chega no seu webhook, abra o Webhook Inspector. O painel “Enriched” renderiza esses tipos com cards dedicados.

Envio para grupo

Para enviar a um grupo, o campo to recebe o objeto { "group_id": "grp_..." } em vez de { "number": "+5511988887777" }, que é a forma usada em 1:1. Veja Visão geral de grupos para detalhes do modelo.

POST /v1/messages: grupo
{
"to": { "group_id": "grp_e442553a56b14e2695f6acfd7d651b1a" },
"content": {
"text": "Bom dia, equipe"
}
}

O campo to é polimórfico. Aceita exatamente uma das três formas (sem kind nem type):

Forma de toDestino
{ "number": "+5511988887777" }Mensagem 1:1 (pessoa)
{ "group_id": "grp_..." }Mensagem para grupo
{ "contact_id": "ct_..." }Mensagem 1:1 via ID de contato Turbo Notify
  • As três formas são mutuamente exclusivas. Envie exatamente uma.
  • group_id é o identificador público grp_{hex32} recebido em webhooks/polling de message.received (to.group_id) ou nos eventos de ciclo de vida de grupo.
  • O objeto content usa o mesmo formato dos envios 1:1 (texto, imagem, vídeo, áudio, documento, figurinha, localização, contato, calendário, botão com link), sem diferenças.
  • Para citar uma mensagem dentro do grupo, use o endpoint dedicado POST /v1/numbers/{ref}/messages/{message_id}/reply.

A resposta tem o formato padrão (message_id, status). O webhook message.sent correspondente usa to.group_id (o mesmo valor que você enviou na requisição); o number_alias do envelope identifica o número que enviou, o que ajuda a relacionar mensagens recebidas e enviadas no mesmo grupo.

Envio por contact_id

Use to.contact_id para enviar a um contato que o Turbo Notify já conhece, sem informar o telefone. O Turbo Notify usa o número registrado nesse contato.

{
"to": { "contact_id": "ct_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" },
"content": { "text": "Olá, tudo bem?" }
}