📄 SKILL.md

← Vault

name: comercialrs-whatsapp-webhook-vps

description: Webhook bidirecional WhatsApp no VPS — recebe respostas de corretores e atualiza tasks via psycopg2 direto

category: devops


ComercialRS — Webhook Bidirecional WhatsApp (VPS)

Contexto

Quando um corretor recebe notificação WhatsApp e responde ("iniciada", "concluida", "remarketing"), o servidor na VPS deve:

1. Receber o webhook da Meta

2. Buscar a task pelo meta_message_id (wamid) em auth.message_log

3. Atualizar auth.tasks.status

4. Enviar confirmação ao corretor via Meta Send API

Arquitetura

Workflow button click (sem context.id)

`python

1. Extrair phone do message.from (5511913412661)

2. phone_cleanup → 11913412661

3. SELECT id FROM public.team_members WHERE phone ILIKE '%11913412661%'

4. SELECT id FROM public.tasks WHERE responsible_id=X AND status IN ('todo','in_progress') ORDER BY created_at DESC LIMIT 1

5. UPDATE status via RPC

6. send_meta_reply(to=5511913412661, text="Reuniao atualizada para X")

`

Colunas do token Meta

automations_config tem meta_access_token e meta_phone_number_id — confirmados no Supabase Cloud.

Deploy/restart

`bash

sshpass -p 'Marcia19671951@' ssh root@31.97.243.106 "fuser -k 8083/tcp 2>/dev/null; sleep 1; nohup python3 /var/www/comercialrs/data/meta_webhook_vps.py &>/var/log/meta_webhook.log &"

sleep 2

sshpass -p 'Marcia19671951@' ssh root@31.97.243.106 "tail /var/log/meta_webhook.log"

`

Auditar fluxo completo (WhatsApp → Kanban)

`bash

1. Quantas tarefas por status?

curl -s ".../rest/v1/tasks?select=status&limit=500" | \

python3 -c "import sys,json; from collections import Counter; print(Counter(t['status'] for t in json.load(sys.stdin)))"

2. Cliques de botão mais recentes (quem clicou, quando, qual status)

curl -s ".../rest/v1/incoming_messages?select=body,parsed_status,task_id,created_at,from_number&order=created_at.desc&limit=20" | \

python3 -m json.tool

3. Tasks que foram atualizadas HOJE (status change, não só new tasks)

curl -s ".../rest/v1/tasks?select=id,status,updated_at&updated_at=gte.2026-06-01T00:00:00Z&order=updated_at.desc&limit=20" | \

python3 -m json.tool

4. Cross-ref: incoming_messages clicadas HOJE vs tasks atualizadas HOJE

Se task_id do clique aparece em updated_at hoje E o status = parsed_status → funcionando

`

Problemas conhecidos

1. PostgREST SSLlocalhost:3000[SSL: WRONG_VERSION_NUMBER] quando chamado da VPS. Solução: usar psycopg2 direto.

2. automations_config sem token Metameta_access_token não existe nessa tabela. Criar colunas ou tabela separada.

3. Meta webhook verification — se o SSL do Kong for autoassinado, a Meta não valida. Curl funciona com -k mas Meta não. Causa: ERR_CONNECTION_RESET. Solução: Let's Encrypt no Kong.

4. Dois servidores — às vezes o servidor velho (8082) e novo (8083) rodam juntos. Matar o da 8082 se não for mais usado.

5. HTTP 200 não enviado em exceção — se update_task_status_rpc levanta exceção sem try/except, wfile.write() nunca é chamado → curl timeout 10s. Sempre usar try/except e garantir HTTP response.

6. Timestamp bigint no incoming_messages — o campo timestamp é bigint, nao text. Passar '' causa invalid input syntax for type bigint. Passar '0' ou omitir o campo.

7. Logging para stdout no nohupprint() nao vai para /var/log/meta_webhook.log no nohup. Usar logging module com filename='/var/log/meta_webhook.log'.

Verificar cliques de botão (source of truth = incoming_messages table)

O log em /var/www/comercialrs/data/meta_webhook_vps.log pode mostrar só "POST /" sem [button]

— isso NÃO significa que os botões não funcionam. O log gravava só POST sem parsear o payload.

Verificar via banco (supabase REST API):

`bash

Listar cliques de botão mais recentes

curl -s "https://dauftiqcvgaydddoxqhh.supabase.co/rest/v1/incoming_messages?select=body,parsed_status,task_id,created_at&order=created_at.desc&limit=50" \

-H "apikey: OtwMAcrs2L3iH60ppShVTrOuQYSolIwITUPVf1ckswk" \

-H "Authorization: Bearer OtwMAcrs2L3iH60ppShVTrOuQYSolIwITUPVf1ckswk"

Contar por status

curl -s ".../incoming_messages?select=parsed_status&limit=500&offset=0" | \

python3 -c "import sys,json; data=json.load(sys.stdin); from collections import Counter; print(Counter(d['parsed_status'] for d in data))"

`

Confirmar que task foi atualizada após clique:

`sql

-- O clique gera incoming_messages.parsed_status='in_progress' E tasks.updated_at=timestamp_do_clique

SELECT t.id, t.status, t.updated_at, im.created_at as clique_time

FROM public.tasks t

JOIN public.incoming_messages im ON im.task_id = t.id

WHERE im.parsed_status IS NOT NULL

ORDER BY im.created_at DESC LIMIT 10;

`

Teste manual

`bash

GET verification

curl "http://31.97.243.106:8083/?hub.mode=subscribe&hub.verify_token=1c526598c56179f772be896d233badab&hub.challenge=TEST"

POST simulando resposta

curl -X POST http://31.97.243.106:8083/ \

-H "Content-Type: application/json" \

-d '{"object":"whatsapp_business_account","entry":[{"changes":[{"value":{"metadata":{"phone_number_id":"578716225306497"},"messages":[{"id":"wamid.DEBUG_ORIG","from":"5511945678901","text":{"body":"iniciada"},"context":{"id":"wamid.DEBUG_ORIG"}}]}}]}]}'

`