Documentação para desenvolvedores
Public API v1
Receba uma cópia das conversas via webhook e manipule conversas, contatos, tags e setores pela API REST.
Visão geral
Webhook de saída
A Névoa faz POST no seu endpoint com mensagens e eventos de ciclo de vida, assinados com HMAC.
API REST
Endpoints em /api/public/v1 autenticados com Authorization: Bearer <apiToken>.
Escopo por número
Vincule integrações META_WHATSAPP em linkedIntegrationIds. Todo payload de conversa inclui o objeto channel.
Quickstart
- No painel Integrações, crie uma integração PUBLIC_API.
- Gere e copie o apiToken e o webhookSecret.
- Informe o webhookUrl (HTTPS) e marque os eventos desejados.
- Selecione os números WhatsApp vinculados — ou deixe vazio para todos.
- Use o Bearer token nas chamadas REST (ex.: POST /messages com phone) e verifique o HMAC nos webhooks.
Base URL
https://web-production-b9668.up.railway.app/api/public/v1Versão atual: v1. Mudanças incompatíveis geram nova versão (v2). A v1 permanece estável. O envelope do webhook inclui apiVersion: "v1".
Autenticação
Todas as rotas em /api/public/v1/** exigem o token da integração PUBLIC_API ACTIVE.
Header
Authorization: Bearer <apiToken>Exemplo
curl -s \
-H "Authorization: Bearer YOUR_API_TOKEN" \
"https://web-production-b9668.up.railway.app/api/public/v1/channels"Rotação de token
- Gere um novo token no painel da integração.
- Atualize o cliente para o novo token.
- Salve a integração — o token antigo deixa de funcionar imediatamente.
- O webhookSecret (HMAC) é independente e pode ser rotacionado da mesma forma.
| Status | Quando |
|---|---|
| 401 | Header ausente, formato inválido, token inexistente ou integração INACTIVE |
| 404 | Recurso fora do escopo linkedIntegrationIds (não vaza existência) |
| 409 | Conflito de negócio (ex.: TEMPLATE_REQUIRED ao enviar free-form fora da janela 24h) |
| 429 | Rate limit da Public API excedido (padrão 120 req/min por integração) |
Canais e escopo
config.linkedIntegrationIds lista as integrações META_WHATSAPP vinculadas. Lista vazia ou ausente = todos os números do tenant (inclusive futuros).
Objeto channel
JSON
{
"integrationId": "wa-uuid",
"name": "WhatsApp Comercial",
"provider": "META_WHATSAPP",
"phoneNumberId": "123",
"displayPhoneNumber": "+5511999999999"
}- Em listagens, use o filtro channelIntegrationId para restringir a um número (deve pertencer ao escopo).
- Rotas com :id de conversa/contato fora do vínculo retornam 404 (não vazam existência).
- Todo payload de mensagem/conversa (API e webhook) inclui o objeto channel.
Canais
Ações — clique para expandir
Endpoints REST
Conversas
Ações — clique para expandir
Mensagens / Templates
Envie free-form por telefone/contato (última conversa) ou inicie com template aprovado.
Ações — clique para expandir
Contatos
Ações — clique para expandir
Catálogos
Ações — clique para expandir
Webhook deliveries
Ações — clique para expandir
Webhooks
A Névoa entrega eventos no seu webhookUrl com envelope versionado e assinatura HMAC.
Envelope e headers
Envelope
{
"id": "uuid-da-entrega",
"event": "message.received",
"apiVersion": "v1",
"occurredAt": "2026-07-19T12:00:00.000Z",
"data": {}
}Content-Type— application/jsonX-Nevoa-Event— Tipo do eventoX-Nevoa-Delivery-Id— ID da entrega (idempotência)X-Nevoa-Timestamp— Unix epoch (segundos)X-Nevoa-Signature— sha256=<hmac-sha256 hex de `${timestamp}.${corpoBruto}`>User-Agent— Nevoa-PublicAPI/1.0
Política de entrega
- Timeout: 10s
- Retries: 5 tentativas, backoff exponencial (5s, 10s, 20s, 40s, 80s)
- Sucesso: HTTP 2xx
- Idempotência: use X-Nevoa-Delivery-Id / id do envelope
- Integração INACTIVE ou isWebhookEnabled=false → entrega DISABLED
- HMAC inclui timestamp; rejeite skew > 300s (anti-replay)
Verificação HMAC
Node.js
const crypto = require('crypto');
function verify(rawBody, secret, signatureHeader, timestampHeader) {
const ts = Number(timestampHeader);
if (!Number.isFinite(ts) || Math.abs(Date.now() / 1000 - ts) > 300) {
return false;
}
const expected =
'sha256=' +
crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Python
import hmac, hashlib, time
def verify(raw_body: bytes, secret: str, signature_header: str, timestamp_header: str) -> bool:
try:
ts = int(timestamp_header)
except (TypeError, ValueError):
return False
if abs(int(time.time()) - ts) > 300:
return False
payload = f"{ts}.".encode() + raw_body
digest = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
expected = f"sha256={digest}"
return hmac.compare_digest(expected, signature_header or "")Catálogo de eventos
Eventos — clique para expandir
Erros
400 — Requisição inválida
Body ou query string fora do contrato: campo obrigatório ausente, enum inválido, filtro não suportado (ex.: assigned=me).
Exemplo
{ "statusCode": 400, "message": ["type must be one of the following values: TEXT, IMAGE, VIDEO, AUDIO, DOCUMENT"], "error": "Bad Request" }401 — Não autorizado
Bearer ausente, inválido ou integração PUBLIC_API inativa.
Exemplo
{ "statusCode": 401, "message": "Token de API inválido ou integração inativa" }404 — Não encontrado (escopo)
Conversa, contato ou canal fora de linkedIntegrationIds. A API responde 404 para não vazar existência.
Exemplo
{ "statusCode": 404, "message": "Conversa não encontrada" }409 — TEMPLATE_REQUIRED
Envio free-form fora da janela de 24h do WhatsApp. Use template.
Exemplo
{
"code": "TEMPLATE_REQUIRED",
"message": "Janela de 24h indisponível. É necessário aguardar resposta do cliente ou usar template."
}429 — Rate limit excedido
Limite de 120 requisições por minuto por integração. Aguarde e tente novamente com backoff.
Exemplo
{ "statusCode": 429, "message": "Limite de requisições da Public API excedido. Tente novamente em instantes." }Changelog
v1 · 2026-07-19
- Provider PUBLIC_API com apiToken, webhookSecret, webhookUrl, subscribedEvents, isWebhookEnabled, linkedIntegrationIds
- Webhook de saída (outbox + HMAC + retries) para 8 tipos de evento
- Objeto channel em payloads de mensagem/conversa
- API REST /api/public/v1 (conversas, mensagens, templates, contatos, catálogos, channels, webhook-deliveries)
- POST /messages — free-form por phone/contactId (conversa mais recente no escopo)