API do WhatsApp
A API da Genial espelha a WhatsApp Cloud API da Meta. Os caminhos e os formatos de requisição e resposta são os mesmos da documentação oficial. Para os recursos listados abaixo (mensagens, templates, mídia e dados do número), só mudam a URL base e o token. Rotas de registro, inscrição de webhooks e sincronização da coexistência são operadas pela Genial e ficam bloqueadas para a chave do cliente.
URL base
https://app.genialsolucoes.com/v1
Substitui
https://graph.facebook.com/v26.0
Autenticação
Cada número conectado tem uma chave própria, no formato gk_live_…. Envie-a no cabeçalho Authorization. A chave só acessa o número e a conta (WABA) a que pertence.
GET/me
Retorna os identificadores do número ligado à chave.
curl https://app.genialsolucoes.com/v1/me \
-H "Authorization: Bearer gk_live_SUA_CHAVE"
{
"phone_number_id": "1234567890",
"waba_id": "9876543210",
"display_phone_number": "+55 33 99999-0000",
"verified_name": "Minha Empresa"
}Enviar mensagens
POST/{PHONE_NUMBER_ID}/messages
Texto livre só funciona até 24 horas depois da última mensagem do contato. Fora dessa janela, use um template.
curl -X POST https://app.genialsolucoes.com/v1/PHONE_NUMBER_ID/messages \
-H "Authorization: Bearer gk_live_SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"to": "5533999990000",
"type": "text",
"text": { "body": "Olá! Seu pedido saiu para entrega." }
}'Template com variável:
{
"messaging_product": "whatsapp",
"to": "5533999990000",
"type": "template",
"template": {
"name": "pedido_enviado",
"language": { "code": "pt_BR" },
"components": [
{ "type": "body", "parameters": [{ "type": "text", "text": "Maria" }] }
]
}
}Imagem, vídeo, áudio, documento, localização, botões e listas seguem o mesmo formato da Meta. Para marcar como lida:
{ "messaging_product": "whatsapp", "status": "read", "message_id": "wamid.HBgM..." }Templates
GET/{WABA_ID}/message_templates
POST/{WABA_ID}/message_templates
DELETE/{WABA_ID}/message_templates?name=nome_do_template
Mídia
POST/{PHONE_NUMBER_ID}/media
Upload em multipart/form-data (até 4 MB por requisição). Retorna o id da mídia para usar no envio.
GET/media/{MEDIA_ID}
Baixa o arquivo de uma mídia recebida. O id vem no webhook, em messages[].image.id, audio.id e assim por diante.
Webhooks
Todo evento que a Meta envia para o número é repassado por POST para a URL cadastrada, no formato original da Meta. Também vem um bloco genial com os identificadores. Os campos field possíveis incluem messages (mensagens e status de entrega), message_template_status_update, account_update smb_message_echoes (mensagens enviadas pelo app no celular, na coexistência), history (conversas antigas do app, até 180 dias, importadas na conexão) e smb_app_state_sync (contatos salvos no celular).
POST https://seu-sistema.com/webhook
X-Genial-Event: messages
X-Genial-Delivery: 5b0f…
X-Genial-Signature: t=1760980000,v1=9c1d…
{
"object": "whatsapp_business_account",
"entry": [{ "id": "WABA_ID", "changes": [{ "field": "messages", "value": { ... } }] }],
"genial": { "instance_id": "…", "field": "messages", "phone_number_id": "…", "waba_id": "…" }
}Validar a assinatura
Calcule o HMAC-SHA256 de {t}.{corpo bruto} com o segredo do webhook e compare com v1. Recuse eventos com t com mais de 5 minutos.
import crypto from "node:crypto";
function isValid(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}Reenvio
Responda com status 2xx em até 10 segundos. Se a resposta for outra ou não vier, o evento é reenviado até 6 vezes, com intervalos crescentes. Use X-Genial-Delivery para ignorar duplicados.
Erros
Erros da Meta são devolvidos sem alteração. Erros da Genial usam o mesmo formato:
{ "error": { "message": "Invalid or missing API key.", "type": "GenialApiException", "code": 401 } }- 401: chave ausente ou inválida.
- 403: a chave não tem acesso a esse número ou recurso, ou o número foi desconectado.