Conceitos
Antes de mergulhar na API, alinhe o vocabulario.
Chip
Um numero de WhatsApp pareado com o hub via Baileys (engenharia reversa do protocolo multidevice). Cada chip:
- Tem um
idULID e umlabellegivel - Mantem socket persistente com servidor WhatsApp
- Tem fila propria (BullMQ) com rate limit isolado por chip
- Pode estar em estados:
pairing,connected,disconnected,logged_out,banned
Sessao Baileys (creds) fica em volume Docker (dev) ou MinIO (prod). Sobrevive a restart do hub.
App
Uma aplicacao integradora (ex: seu CRM, atendimento, chatbot). Cada app:
- Tem
api_key(Bearer token) ewebhook_secret(pra HMAC) - Pode ter 1 ou N chips vinculados via
app_chip_access - Recebe webhooks dos eventos dos chips vinculados
Vinculo (app_chip_access)
Tabela que define qual app pode usar qual chip. Campos:
can_send— pode enviar mensagens via esse chipcan_receive— recebe webhooks de mensagens recebidasreceive_self_chat— opt-in pra receber mensagens que o chip mandou pra si mesmo (uso: linha de comando do operador)transcribe_audio_mode—'off'|'all'|'whitelist'— controla transcricao automatica de audiostranscribe_audio_jids— whitelist de JIDs pra transcricao parcial
Mensagem (messages)
Cada mensagem inbound (recebida) ou outbound (enviada via API ou manualmente do celular) gera um row.
Campos chave:
direction—'in'ou'out'type—text,image,audio,document,location,reaction,unknowncontent— JSONB variavel por tipowa_message_id— id no protocolo WhatsApp (chave pra dedup)chip_id,app_id,from_jid,to_jid,chat_jidstatus—queued,sent,delivered,read,failed(so outbound)
Evento
Webhooks que o hub dispara pras apps consumidoras. Lista completa: Eventos.
Tipos:
- Mensagem —
message.received,message.status,message.transcribed - Chip —
chip.connected,chip.disconnected,chip.logged_out,chip.banned,chip.qr_loop,chip.bad_session_streak,chip.silent
Cada delivery e assinada com HMAC SHA-256 + retry exponencial (7 tentativas: 30s → 24h).
Auditoria (audit_events)
Toda mutacao admin (criar app, atualizar webhook_url, replay delivery, etc) grava entry imutavel em audit_events. Trigger Postgres bloqueia UPDATE/DELETE.
Quem (actor_id, actor_type), quando, em qual recurso, antes/depois — tudo registrado.
Ver ADR 007 pra justificativa do design append-only.
Identidades duplas — JID vs LID
WhatsApp esta migrando contatos pra LID (List ID) por privacidade. Um mesmo contato pode aparecer:
- como
5511999998888@s.whatsapp.net(JID telefone — caminho tradicional) - como
12345678901234@lid(LID — quando contato ativa privacidade “Numero de telefone: ninguem”)
Hub trata os 2 e cruza quando possivel:
sender.jid— identidade principal que veio na mensagemsender.lid— LID alternate quando WA expoe (cross-match)sender.phone_number— telefone “puro” extraido (vazio se nao expoe)
Anti-ban
Hub aplica multiplas camadas pra reduzir risco de WhatsApp banir o chip:
- Throttle por chip via BullMQ rate limiter
- Jitter ±30% nos delays entre mensagens
- Presenca (
composingantes de texto,recordingantes de audio) - Warmup automatico pra chips novos (30 msg/dia → cresce gradualmente)
- Limite diario com reset 00h UTC
- Detector de ban via sliding window (3 sintomas/h → marca
banned, pausa fila, dispara webhook)
Ver Anti-ban (em breve) pra detalhes.
Idempotencia
POST /v1/messages aceita campo idempotency_key. Hub mantem unique constraint (app_id, idempotency_key). Reenvio com mesma key retorna a mensagem original — nao duplica.
Use UUID v4 ou ULID pra cada operacao logica do seu lado.
Versionamento
API e versionada via path: /v1/.... Mudancas breaking criam /v2. Adicoes nao-breaking entram em /v1 sem versao nova — ver changelog.