Mensagens
Mande texto, modelo, imagem ou documento para um contato no WhatsApp ou no Instagram, ou para uma conversa do chat do site. O BoaVoz confere tudo o que sabe antes de chamar a Meta e diz o motivo quando não dá.
messagesPacoteIntegrações (R$ 49 por mês, por conta). Sem ele, a API responde 403 plan_not_allowed.| Rota | O que faz |
|---|---|
POST /v1/messages | Envia texto, modelo, imagem ou documento. |
GET /v1/messages/{id} | A mensagem, com o status (sent, delivered, read, failed, uncertain). |
GET /v1/bots/{id}/templates | Os modelos do número do WhatsApp do chatbot e se dá para enviar cada um pela API. |
POST/v1/messages
WhatsApp e Instagram: bot_id e to, o endereço do contato. Chat do site: conversation_id, de uma conversa que o visitante abriu. O type escolhe o resto do corpo.
curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "text",
"text": "Teste da API do BoaVoz"
}'{
"message_id": "msg_48211",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "text",
"text": "Seu pedido saiu para entrega.",
"agent_name": "Ana",
"sender": "postman"
}'{
"message_id": "msg_48212",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}agent_name faz a mensagem chegar como de alguém da equipe (“*Ana:* …” no WhatsApp); sender é quem mandou no seu sistema e volta no webhook message.sent.
curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"conversation_id": "conv_5d2a9e1b-3c4f-4b6a-8e7d-2f1a0b9c8d7e",
"type": "text",
"text": "Oi! Aqui é o sistema integrado.",
"agent_name": "Ana"
}'{
"message_id": "msg_48213",
"conversation_id": "conv_5d2a9e1b-3c4f-4b6a-8e7d-2f1a0b9c8d7e",
"status": "sent"
}curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "image",
"image": {
"url": "https://loja.exemplo.com.br/fotos/pedido-1234.jpg"
},
"text": "Foto do seu pedido"
}'{
"message_id": "msg_48214",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "document",
"document": {
"url": "https://loja.exemplo.com.br/boletos/1234.pdf",
"filename": "Boleto teste.pdf"
},
"text": "Segue o seu boleto"
}'{
"message_id": "msg_48215",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "template",
"template": {
"name": "pedido_saiu",
"language": "pt_BR",
"variables": [
"Ruan"
]
}
}'{
"message_id": "msg_48216",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}Fora da janela de 24 horas (o contato não escreveu nesse tempo), só sai modelo aprovado. Confira os modelos e o número de variáveis de cada um em GET /v1/bots/{id}/templates.
curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3b9f2c8e-5a1d-4e7b-9c6f-2d8a4e1b7c90" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "text",
"text": "Quer receber o cardápio do dia?",
"components": {
"type": "buttons",
"buttons": [
{
"title": "Sim, quero",
"id": "quero_cardapio"
},
{
"title": "Agora não",
"id": "agora_nao"
}
]
}
}'{
"message_id": "msg_48217",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}Botões, lista, link e carrossel vão em components, junto de um texto. O formato e como cada um fica em cada canal estão em Mensagens ricas.
Regras e erros dos campos
| Campo | Regra | Erro |
|---|---|---|
bot_id | Obrigatório no WhatsApp e no Instagram: o id com bot_, de um chatbot do escopo da chave. | 403 forbidden_scope |
to | Obrigatório no WhatsApp e no Instagram: ctc_…, phone:55…, wa:<BSUID>, ig:<id> ou ext:<id>. Contato que não existe no chatbot: 404. | 400 to |
channel | whatsapp ou instagram. Obrigatório com ext:; com os outros formatos, se vier, precisa bater com o do to. | 400 channel |
conversation_id | Só no chat do site: conv_…, de uma conversa do site. Não vai junto com to. | 400 conversation_id |
type | text, template, image ou document. No chat do site, não há modelo. | 400 type |
text | Com text: obrigatório, até 4.096 caracteres (com components, até 1.024). Com imagem e documento: a legenda, até 1.024. Com modelo: não mande (o texto vem do modelo). | 400 text |
image, document | {url, filename?}: url HTTPS pública (até 2.048 caracteres); filename até 200. Imagem: JPEG ou PNG até 5 MB. Documento: PDF, Word, Excel, PowerPoint, TXT ou CSV até 16 MB. No Instagram, PDF e imagem até 8 MB; no site, documento só em PDF. O BoaVoz confere o tipo pelos primeiros bytes. | 400 image.url, document.url, ….filename |
template | {name, language?, variables?}: o nome de um modelo aprovado do número, o idioma (padrão pt_BR) e uma variável por {{1}}, {{2}}…, na ordem (até 20, cada uma até 1.024). Só modelos de utilidade e de marketing; o de marketing pede o aceite de novidades. | 400 template.name, template.language, template.variables |
components | Botões, lista, link ou carrossel, só com type: text (formato). | 400 components…; 422 prohibited_content |
agent_name | Opcional: assina como alguém da equipe (até 80 caracteres). | 400 agent_name |
sender | Opcional: quem mandou no seu sistema (até 64: letras, números, espaço, ponto e hífen). | 400 sender |
O que o BoaVoz confere antes de mandar
| Erro | Quando |
|---|---|
422 outside_messaging_window | O contato não escreveu nas últimas 24 horas: no WhatsApp, só modelo; no Instagram, nada. |
422 channel_not_connected | O chatbot não tem o canal conectado, ou o cliente tirou o acesso do BoaVoz (conecte de novo no painel). |
422 bot_paused | O chatbot está pausado pelo dono: nada sai pela API até ele ser retomado. |
422 bot_without_size | Modelo num chatbot sem tamanho: campanhas, lembretes e modelos só saem de chatbot com tamanho. |
422 contact_suppressed | O contato pediu para apagar os dados: está na lista de supressão. |
422 contact_opted_out | O contato pediu para não receber esse tipo de mensagem (SAIR, botão ou o próprio WhatsApp). |
422 no_marketing_consent | Modelo de marketing para quem não aceitou novidades (ou disse que não tem 18 anos). |
422 prohibited_content | O portão barrou o texto, um título ou o modelo pelas regras da Meta (o texto nunca é editado). |
422 channel_rejected | A Meta recusou; details.channel_code traz o código dela. |
403 feature_suspended | O canal está suspenso, ou o negócio ainda não fez o aceite do canal. |
- Deu certo: 201 com
"status": "sent". Sem resposta da Meta no prazo: 202 com"status": "uncertain"; o status da Meta concilia depois (webhookmessage.statusoumessage.failed). O BoaVoz nunca reenvia sozinho: para tentar de novo, use a mesma Idempotency-Key. - Erro temporário da Meta: 503 ou 429 com
Retry-After.
curl -X POST "https://boavoz.com/api/v1/messages" \
-H "Authorization: Bearer $BOAVOZ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-1234-saiu" \
-d '{
"bot_id": "bot_7c9e6679-7425-40de-944b-e07fc1f90ae7",
"to": "phone:5511999990000",
"type": "text",
"text": "Mensagem idempotente"
}'{
"message_id": "msg_48218",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"status": "sent"
}message_id, com o cabeçalho Idempotent-Replayed: true, e só uma mensagem chega ao contato.GET/v1/messages/{id}
A mensagem no mesmo formato do histórico. status: received (do contato), pending, sent, delivered, read, failed (com error.code) ou uncertain. source: contact, ai, human (equipe), api, campaign ou phone_app (o app do celular, na coexistência).
curl "https://boavoz.com/api/v1/messages/msg_48211" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"id": "msg_48211",
"conversation_id": "conv_0e8f5a3c-2b1d-4c6e-9f7a-1d2c3b4a5e6f",
"direction": "outbound",
"source": "api",
"text": "Teste da API do BoaVoz",
"media": null,
"agent": {
"type": "api",
"display_name": "Integração",
"sender": null
},
"status": "read",
"error": null,
"deleted": false,
"edited": false,
"reply_to": null,
"reactions": {
"contact": null,
"agent": null
},
"created_at": "2026-10-19T15:02:11.481Z"
}GET/v1/bots/{id}/templates
Os modelos do número do WhatsApp do chatbot, com a categoria, o status da Meta, o texto e o número de variáveis. sendable diz se dá para mandar pela API (aprovado, de utilidade ou de marketing e num formato que o BoaVoz envia); quando não dá, unsupported_reason diz por quê. Sem WhatsApp conectado: 422 channel_not_connected.
curl "https://boavoz.com/api/v1/bots/bot_7c9e6679-7425-40de-944b-e07fc1f90ae7/templates" \
-H "Authorization: Bearer $BOAVOZ_API_KEY"{
"data": [
{
"name": "pedido_saiu",
"language": "pt_BR",
"category": "utility",
"status": "approved",
"rejected_reason": null,
"body": "Oi, {{1}}! O seu pedido saiu para entrega.",
"variables": 1,
"sendable": true,
"unsupported_reason": null
},
{
"name": "promo_sexta",
"language": "pt_BR",
"category": "marketing",
"status": "pending",
"rejected_reason": null,
"body": "{{1}}, a sexta chegou com 10% de desconto no cardápio!",
"variables": 1,
"sendable": false,
"unsupported_reason": null
}
]
}