Turbo Notify no Supabase
Quando uma linha muda no seu projeto Supabase, o seu cliente recebe uma mensagem de WhatsApp. Um Database Webhook chama uma Edge Function, e a função envia a mensagem pela API do Turbo Notify. A função é pequena, não tem dependências e vem com os seus testes, no repositório de exemplos (abre em nova aba).
O que você precisa
Seção intitulada “O que você precisa”- Uma conta do Turbo Notify com um número conectado (começo rápido).
- Uma chave de API só com a permissão de enviar mensagens (
messages:send), criada em API Keys (abre em nova aba). - Um projeto Supabase e a CLI do Supabase, autenticada e ligada ao projeto.
- Uma tabela com o telefone do cliente em formato internacional (
+e o código do país, sem espaços) e uma coluna que registra se a pessoa concordou em receber mensagens de WhatsApp. O exemplo usaphoneewhatsapp_opt_in.
Conectar
Seção intitulada “Conectar”-
Copie a pasta da função
supabase/functions/notify-whatsappdo exemplo para o seu projeto e acrescente este bloco ao seusupabase/config.toml:supabase/config.toml [functions.notify-whatsapp]verify_jwt = falseO banco chama a função sem um token de usuário, então a verificação de token da plataforma fica desligada para esta função. A função confere um segredo próprio (próximo passo).
-
Crie o segredo que o banco vai enviar e guarde-o, junto com a sua chave, como segredos da função:
openssl rand -hex 32supabase secrets set TN_API_KEY=SUA_CHAVE WEBHOOK_SECRET=O_VALOR_ACIMA -
Publique (o CLI empacota a função num contêiner, então o Docker precisa estar rodando):
supabase functions deploy notify-whatsapp -
No dashboard do Supabase, abra Integrations, depois Database Webhooks, e crie um webhook:
- Tabela: a sua (o exemplo usa
orders), com os eventos Insert e Update. - Tipo: Supabase Edge Functions, função
notify-whatsapp, métodoPOST. - Cabeçalho HTTP:
x-webhook-secretcom o valor que você gerou.
Criar pelo dashboard mantém o segredo fora do seu repositório, e o dashboard ativa a extensão
pg_netque os webhooks usam. O exemplo traz o mesmo webhook em SQL emsupabase/webhook.sql, com marcadores no lugar dos valores. Num projeto hospedado, ative os Database Webhooks uma vez no dashboard antes de aplicá-lo: o SQL usa o schemasupabase_functions, e um projeto que nunca ativou webhooks não o tem, então o arquivo falha comschema "supabase_functions" does not existe não muda nada. A primeira instrução dele ativa opg_net; sem essa extensão, todo insert e update na tabela falha. - Tabela: a sua (o exemplo usa
-
Mude o que é enviado em
message.ts: ele decide quais eventos geram mensagem e o que o texto diz.
O Turbo Notify só precisa da chave de API, e ela fica como segredo do Supabase: nunca numa tabela, nunca no repositório. Crie a chave só com messages:send. Se ela vazar, o máximo que consegue é enviar mensagens, e você a revoga em API Keys (abre em nova aba) sem mexer em mais nada.
A função tem ainda uma segunda proteção do lado do Supabase: só aceita uma chamada que traga o x-webhook-secret que você definiu. Ninguém consegue disparar uma mensagem chamando o endereço da função.
Primeiro um teste que não envia nada. Chame a função com uma linha que não concordou em receber mensagens (troque o endereço e o segredo):
curl -X POST https://SEU_PROJETO.supabase.co/functions/v1/notify-whatsapp \ -H "x-webhook-secret: O_VALOR_ACIMA" \ -d '{"type":"INSERT","table":"orders","schema":"public","record":{"id":1,"phone":"+12025550123","whatsapp_opt_in":false},"old_record":null}'A resposta é {"skipped":"no_opt_in"}. Com um segredo errado, a resposta é 401.
Depois o teste de verdade: insira uma linha na sua tabela com o seu próprio número e a coluna de consentimento verdadeira. Em alguns segundos a mensagem chega no seu celular. A função responde ao banco na hora; se a mensagem foi entregue chega depois, por webhook ou polling.
Para testar o caminho inteiro sem um projeto hospedado, rode no Supabase local. O README do exemplo (abre em nova aba) traz os comandos. Rodamos exatamente esse caminho: uma linha com consentimento gerou a mensagem no celular, o mesmo evento enviado duas vezes gerou uma só mensagem, e uma linha sem consentimento não enviou nada.
Atualizar
Seção intitulada “Atualizar”Mude a função e rode supabase functions deploy notify-whatsapp de novo. O endereço do Turbo Notify nunca muda.
Limites
Seção intitulada “Limites”- O consentimento é seu. Envie só para quem concordou em receber mensagens de WhatsApp de você. O exemplo recusa uma linha em que a coluna de consentimento não seja verdadeira: sem o registro, a mensagem não sai.
- Um número conectado como o WhatsApp Web. O Turbo Notify conecta o seu número como um aparelho vinculado, sem cadastro na Meta e sem aprovação de modelo. É um serviço independente, sem afiliação com a Meta, e cada envio segue um ritmo que ajuda a proteger o número. Quem decide sobre restrições é o WhatsApp, e um número pode ser restringido qualquer que seja o ritmo. As práticas que o mantêm saudável estão em Proteja o seu número.
- A cota e o ritmo do seu plano valem para cada mensagem que a função envia, como para qualquer outro envio. Veja Limites.
- Um evento, uma mensagem. A função envia com cada mensagem uma chave que identifica o evento, então o mesmo evento entregue duas vezes é enviado uma só.
- Falhas. A função responde
502quando tentar de novo pode ajudar (um limite de taxa, número desconectado, uma indisponibilidade do Turbo Notify) e200com o motivo quando não pode (um pedido inválido). Quando o problema é a conta (a assinatura não está ativa, ou a cota de mensagens ou de contatos do plano acabou até o ciclo virar) ou a chave está errada, responde500e o motivo aparece nos logs da função, para que as notificações não sejam descartadas em silêncio. - Projetos hospedados. Rodamos esse caminho no Supabase local e num projeto hospedado novo: a tabela, os segredos e a publicação, uma linha com consentimento gerando a mensagem, a mudança de status gerando a segunda, e o mesmo evento enviado de novo devolvendo a mesma mensagem. No projeto hospedado o banco chamou a função direto pelo
pg_net. Não rodamos lá osupabase/webhook.sqlem si, nem o formulário do webhook no dashboard. A função não depende de o Supabase chamá-la de novo depois de uma resposta com falha: o mesmo evento é enviado uma só vez de qualquer forma.