Skip to content

MatheusHenriquePrates/uazapi-webhook

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PT-BR   EN

PT-BR

matheus@devops:~$ cat sobre.txt

Receptor de webhook grau-de-produção pra UAZAPI (gateway HTTP de WhatsApp). Persiste toda mensagem inbound antes de fazer qualquer coisa, agrupa burst do mesmo sender com janela de debounce configurável, e dispatcha os grupos resultantes pra rotas configuráveis — com retry de backoff exponencial, dead-letter queue, e uma API admin.

  • Fastify 5 + Node 20, ~1.5k LoC, três deps (fastify, pg, pino)
  • Zero loss by design — todo webhook cai em raw_messages (PG) antes do handler retornar 200 pra UAZAPI; duplicata colapsa em UNIQUE(uazapi_message_id)
  • Debounce buffer — janela deslizante por (sender, chat) dá flush depois de N segundos de silêncio (default 8s), previne tempestade de mensagens downstream
  • Routes são dado, não código — destinos vivem em webhook_routes e podem ser editados em runtime via API admin
  • Manifests K8s inclusos — namespace, deployment hardened (non-root, seccompProfile: RuntimeDefault, drop: [ALL]), NetworkPolicies (default-deny + 5 allows explícitos), probes de readiness/liveness
  • Transcrição de áudio opcional — opt-in por rota, baixa da UAZAPI, descriptografa mídia WhatsApp (HKDF + AES-256-CBC), transcreve via Groq Whisper
matheus@devops:~$ ls stack/

Node.js Fastify PostgreSQL Docker Kubernetes WhatsApp

matheus@devops:~$ cat arquitetura.txt
UAZAPI (gateway WhatsApp)
        │
        │ POST /webhook/{secret}
        ▼
┌──────────────────────┐
│   uazapi-webhook     │   1) Insere em raw_messages (PG)
│   Fastify + Node 20  │      UNIQUE(uazapi_message_id) → idempotente
│   (porta 4600)       │   2) Retorna 200 OK imediatamente
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│   Debounce engine    │   Agrupa por (sender, chat); flush depois
│   Map em memória     │   de 8s de silêncio (DEBOUNCE_MS)
└──────────┬───────────┘
           │
           ▼
┌──────────────────────┐
│ message_groups (PG)  │
└──────────┬───────────┘
           │ SELECT … FROM webhook_routes
           │ WHERE chat_jid_filter / instance_id_filter match
           │ ORDER BY priority DESC LIMIT 1
           ▼
┌──────────────────────┐
│ Router / Dispatcher  │   destination_type ∈ { log, http }
│   (com retry)        │   transcribe_audio? → chama transcriber
└──────────┬───────────┘
           │
       ┌───┴────────────────────────┐
       ▼                            ▼
   delivered                  retry × N → dead_letters
matheus@devops:~$ ls endpoints/
Método Path Auth Pra quê
POST /webhook/:secret secret na URL Webhook inbound da UAZAPI
GET /health nenhuma Liveness/readiness
GET /api/stats X-API-Key Counts de raw_messages / message_groups / dead_letters
GET /api/queue X-API-Key Buffer de debounce em memória
GET /api/dead-letters X-API-Key Dispatches falhados (paginado)
POST /api/retry/:id X-API-Key Re-dispatch de um grupo falhado
GET / POST / PUT / DELETE /api/routes X-API-Key CRUD de rotas
GET / POST /api/groups X-API-Key Helpers de client_groups
POST /api/groups/:id/connect X-API-Key Registra essa URL de webhook na UAZAPI pra instância do grupo
POST /api/groups/connect-all X-API-Key Mesma coisa, pra todo grupo habilitado
matheus@devops:~$ ./quick-start.sh
git clone https://github.com/MatheusHenriquePrates/uazapi-webhook.git
cd uazapi-webhook

# 1. Configura
cp .env.example .env
# edita .env: no mínimo WEBHOOK_SECRET, ADMIN_API_KEY, DATABASE_URL

# 2. Schema
psql "\$DATABASE_URL" -f sql/init.sql
psql "\$DATABASE_URL" -f sql/002_group_routing.sql

# 3. Roda
docker build -t uazapi-webhook:latest .
docker run --rm --env-file .env -p 4600:4600 uazapi-webhook:latest

# 4. Sanity check
curl -s http://localhost:4600/health
# {"status":"ok","uptime":3,"timestamp":"..."}
matheus@devops:~$ cat routes.txt

Uma rota é uma linha em webhook_routes descrevendo pra onde (e como) encaminhar grupos de mensagem debouncados. O router pega a rota habilitada de maior prioridade cujos chat_jid_filter e instance_id_filter batem (NULL = wildcard).

Forward de tudo pra sua API:

curl -X POST http://localhost:4600/api/routes \
  -H "X-API-Key: \$ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "forward-all",
    "destination_type": "http",
    "destination_config": {
      "url": "https://my-app.example.com/incoming-whatsapp",
      "headers": { "Authorization": "Bearer my-app-token" },
      "timeout_ms": 30000
    },
    "enabled": true,
    "priority": 10
  }'

Pra transcribe_audio: true de fato funcionar você precisa setar UAZAPI_BASE_URL, UAZAPI_INSTANCE_TOKENS_JSON, e GROQ_API_KEY.

Payload dispatchado pra destination_type = http:

{
  "groupId": "uuid",
  "senderJid": "5511...@s.whatsapp.net",
  "chatJid": "120000000000000000@g.us",
  "instanceId": "default",
  "messageCount": 3,
  "message": "[WhatsApp] From: 5511...\nChatJid: ...\nMessages: 3\n---\n...",
  "transcription": null,
  "messages": [{ "id": "...", "type": "text", "text": "...", "pushName": "...", "timestamp": "...", "payload": { } }]
}
matheus@devops:~$ cat schema.txt

Quatro tabelas; veja sql/init.sql e sql/002_group_routing.sql:

Tabela Lifecycle
raw_messages queuedgrouped (depois do flush do debounce)
message_groups pendingdelivered | failed
webhook_routes Config estática; input principal do router
client_groups Helper opcional pros endpoints /api/groups
dead_letters Uma linha por message_group que esgotou retries
matheus@devops:~$ cat k8s-deploy.txt
# Build e import da imagem no k3s
docker build -t uazapi-webhook:latest .
docker save uazapi-webhook:latest | sudo k3s ctr images import -

# Edita o secret com valores reais, aplica
cp k8s/secret.example.yaml k8s/secret.yaml

kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/networkpolicy.yaml

kubectl get pods -n uazapi-webhook
kubectl logs -n uazapi-webhook deploy/uazapi-webhook -f

O deployment vem hardened por default: runAsNonRoot, seccompProfile: RuntimeDefault, drop: [ALL], e seis NetworkPolicy (default-deny-all + allows explícitos pra DNS, HTTPS egress, Postgres, porta inbound do webhook, e relay opcional).

matheus@devops:~$ cat limitacoes.txt
  • O buffer de debounce é in-memory. No crash, raw_messages ainda em queued são recuperados no startup e re-alimentados no buffer — mas um flush em voo pode se perder. O dead-letter é a rede de segurança.
  • O dispatcher só implementa log e http. Adiciona destination_type próprio estendendo attemptDispatch em src/router.js.
  • Sem streaming, sem rate-limit inbound. Põe reverse proxy na frente se expõe o webhook na Internet pública.
  • A comparação estática estilo BEARER_TOKEN da API key não é constant-time. Trata o host como appliance privado.
matheus@devops:~$ cat LICENSE

MIT — veja LICENSE.

matheus@devops:~$ contact

LinkedIn Email

matheus@devops:~$ _

EN

matheus@devops:~$ cat about.txt

Production-grade webhook receiver for UAZAPI (WhatsApp HTTP gateway). Persists every inbound message before doing anything else, groups bursts from the same sender with a configurable debounce window, and dispatches the resulting message groups to configurable routes — with exponential-backoff retry, dead-letter queue, and an admin API.

  • Fastify 5 + Node 20, ~1.5k LoC, three deps (fastify, pg, pino)
  • Zero loss by design — every webhook lands in raw_messages (PG) before the handler returns 200 to UAZAPI; duplicates collapse on UNIQUE(uazapi_message_id)
  • Debounce buffer — sliding window per (sender, chat) flushes after N seconds of silence (default 8s)
  • Routes are data, not code — destinations live in webhook_routes and can be edited at runtime through the admin API
  • K8s manifests included — namespace, hardened deployment, NetworkPolicies (default-deny + 5 explicit allows), readiness/liveness probes
  • Optional audio transcription — opt-in per route, downloads from UAZAPI, decrypts WhatsApp media (HKDF + AES-256-CBC), transcribes via Groq Whisper
matheus@devops:~$ ls stack/

Node.js Fastify PostgreSQL Docker Kubernetes WhatsApp

matheus@devops:~$ cat endpoints.txt
Method Path Auth Purpose
POST /webhook/:secret URL secret Inbound UAZAPI webhook
GET /health none Liveness/readiness
GET /api/stats X-API-Key Counts of raw_messages / message_groups / dead_letters
GET /api/queue X-API-Key Current in-memory debounce buffer
GET /api/dead-letters X-API-Key Failed dispatches (paginated)
POST /api/retry/:id X-API-Key Re-dispatch a failed message group
GET / POST / PUT / DELETE /api/routes X-API-Key CRUD on routes
GET / POST /api/groups X-API-Key Helpers for client_groups
matheus@devops:~$ ./quick-start.sh
git clone https://github.com/MatheusHenriquePrates/uazapi-webhook.git
cd uazapi-webhook

cp .env.example .env
# edit .env: at minimum WEBHOOK_SECRET, ADMIN_API_KEY, DATABASE_URL

psql "\$DATABASE_URL" -f sql/init.sql
psql "\$DATABASE_URL" -f sql/002_group_routing.sql

docker build -t uazapi-webhook:latest .
docker run --rm --env-file .env -p 4600:4600 uazapi-webhook:latest

curl -s http://localhost:4600/health
matheus@devops:~$ cat schema.txt
Table Lifecycle
raw_messages queuedgrouped (after debounce flush)
message_groups pendingdelivered | failed
webhook_routes Static config; primary input to the router
client_groups Optional helper for the /api/groups endpoints
dead_letters One row per message_group that exhausted retries
matheus@devops:~$ cat limitations.txt
  • The debounce buffer is in-memory. On crash, raw_messages rows still in queued are recovered at startup and re-fed into the buffer — but a flush in flight can be lost.
  • The dispatcher only implements log and http. Add your own destination_type by extending attemptDispatch in src/router.js.
  • No streaming, no inbound rate-limiting. Put a reverse proxy in front if you expose the webhook to the public Internet.
  • The static BEARER_TOKEN-style API key comparison is not constant-time. Treat the host as a private appliance.
matheus@devops:~$ cat LICENSE

MIT — see LICENSE.

matheus@devops:~$ contact

LinkedIn Email

matheus@devops:~$ _

About

Production-grade UAZAPI (WhatsApp) webhook receiver with Postgres queue, debounce and routing | Receptor de webhook UAZAPI (WhatsApp) grau de produção com fila Postgres, debounce e roteamento

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors