Supabase
Usuários do Supabase Auth viram contatos, e os e-mails de autenticação saem pela Postal com o Send Email Hook.
A integração do Supabase tem duas partes, na mesma conexão: os usuários do Supabase Auth viram contatos (com eventos de cadastro, confirmação e exclusão), e os e-mails de autenticação do seu app saem pela Postal com o Send Email Hook.
#Crie a conexão
No painel, abra Integrações › Seu app e clique em Conectar no cartão do Supabase. A conexão tem a sua URL, que você cola no provedor, e mostra o passo a passo na própria tela.
https://api.postal.so/integrations/crm/01a1c2d3-e4f5-7a6b-8c9d-0e1f2a3b4c5d/webhook
No Supabase, abra Integrations › Database Webhooks e crie um webhook na tabela auth.users com Insert, Update e Delete. Em HTTP Request, escolha POST e cole a URL da conexão. Em HTTP Headers, adicione:
X-Postal-Secret: whsec_… (o segredo mostrado na conexão)
O segredo é da conexão e pode ser trocado na tela dela (o antigo para de valer). Também vale Authorization: Bearer <segredo>.
As integrações de app contam no limite do plano (app_integrations). Fora do plano, os cartões aparecem bloqueados com o botão Fazer upgrade.
#Eventos
| Mudança em auth.users | Evento na Postal | Padrão |
|---|---|---|
INSERT | supabase.user.created | ligado |
UPDATE que confirma o e-mail | supabase.user.confirmed | ligado |
UPDATE que só muda o último login | supabase.user.signed_in | desligado |
Outro UPDATE (e-mail, metadados) | supabase.user.updated | ligado |
DELETE | supabase.user.deleted (exclusão) | ligado |
As propriedades são user_id, provider, email_confirmed, created_at e last_sign_in_at. Mudanças em outras tabelas são ignoradas.
#Qual contato
O usuário é casado pelo ID do Supabase, guardado no external_id do contato: se o e-mail mudar, o mesmo contato é atualizado. O nome vem dos metadados do usuário, de first_name e last_name (ou de full_name / name):
await supabase.auth.signUp({
email: '[email protected]',
password,
options: { data: { first_name: 'Fulano', last_name: 'Silva' } },
})
Para as exclusões, a conexão diz o que fazer com o contato: só registrar o evento (padrão), descadastrar o contato (ele continua na audiência, sem receber marketing) ou excluir o contato (sem evento, já que o contato some). Uma exclusão nunca cria um contato que a Postal não tinha.
#Configurações da conexão
- Eventos: só os marcados viram contato e evento; os outros são ignorados (a resposta ainda é
202). - Sincronizar o nome: atualiza nome e sobrenome do contato com o que vier do provedor.
- Adicionar ao segmento e Inscrever no tópico: um segmento estático e um tópico para cada contato que chega.
- Quando o usuário for excluído no app: só registrar, descadastrar ou excluir o contato.
Tudo que a conexão muda no contato leva a origem crm:<id da conexão> (last_change_source), e cada entrega aparece no registro da conexão, com o resultado de cada pessoa. Uma entrega repetida pelo provedor (mesmo ID) não é processada duas vezes.
#E-mails de login (Send Email Hook)
Com o Send Email Hook, o Supabase entrega cada e-mail de autenticação à Postal em vez de enviar. Para ligar:
- Na conexão, em E-mails de login pelo Postal, ligue o envio, escolha o remetente (de um domínio verificado do seu time) e, se quiser, a URL do projeto (
https://abcd.supabase.co). - No Supabase, abra Authentication › Hooks, adicione um hook Send Email do tipo HTTPS com a URL do hook mostrada na conexão e gere o segredo.
- Copie o segredo (
v1,whsec_…) e cole na conexão. Salve.
https://api.postal.so/integrations/supabase/01a1c2d3-e4f5-7a6b-8c9d-0e1f2a3b4c5d/send-email
| email_action_type | Modelo padrão (assunto) |
|---|---|
signup | Confirme seu cadastro |
magiclink | Seu link de acesso |
recovery | Redefina sua senha |
invite | Você recebeu um convite |
email_change | Confirme a troca de e-mail (com a troca segura, um e-mail para o endereço atual e outro para o novo) |
reauthentication | Seu código de confirmação |
Cada tipo tem um modelo em português que você edita na conexão (assunto e HTML). Variáveis:
| Variável | O que é |
|---|---|
{{{CONFIRMATION_URL}}} | O link de confirmação. Com a URL do projeto: https://abcd.supabase.co/auth/v1/verify?token=…&type=…&redirect_to=…. Sem ela: {site_url}/auth/confirm?token_hash=…&type=…&next=…, para quem confirma no próprio app (SSR). |
{{{TOKEN}}} | O código de 6 dígitos (OTP). |
{{{TOKEN_HASH}}} | O hash do token, para montar o seu próprio link. |
{{{EMAIL}}}, {{{NEW_EMAIL}}} | O e-mail do usuário e, na troca, o novo e-mail. |
{{{SITE_URL}}}, {{{REDIRECT_TO}}} | A Site URL do projeto e o destino depois da confirmação. |
Os e-mails passam pelo mesmo caminho do POST /emails: domínio verificado, cotas diária e mensal e fila prioritária. Eles levam a tag supabase_auth com o tipo e aparecem em E-mails. Os tipos de aviso de segurança (password_changed_notification e outros) são aceitos sem envio.
A resposta segue o que o Supabase espera: {} com 200 quando o e-mail foi para a fila, e, nos erros, o status com o motivo, que aparece em Logs › Auth no Supabase:
{
"error": {
"http_code": 403,
"message": "The exemplo.com domain is not verified. Please, add and verify your domain."
}
}
| Status | Quando |
|---|---|
401 | Assinatura ausente ou inválida: o segredo colado na conexão não é o do hook. |
403 | O domínio do remetente não está verificado, o envio está pausado ou a conta está suspensa. |
409 | Os e-mails de login estão desligados na conexão, ou a conexão está pausada. |
422 | A conexão não tem remetente, ou o hook não trouxe e-mail. |
429 | A cota diária ou mensal de envios acabou. |
#Dispare automações
Cada evento fica no contato com o nome supabase.user.created e as propriedades da tabela acima. Na tela da conexão, o botão Criar automação ao lado de cada evento abre uma automação nova com o gatilho Evento recebido já preenchido. Pelos endpoints de automações, o gatilho é {"type": "event", "event": "supabase.user.created"}.
Exemplo: uma sequência de boas-vindas a partir do cadastro, e um lembrete para quem não confirmou o e-mail em 2 dias (com uma condição sobre supabase.user.confirmed). Nos e-mails, as propriedades do evento entram como {{event.amount}} nos passos ou como variáveis do template ({{{amount}}}).