Notificações Push
FCM nos três backends. Setup automático, APNs no iOS, deep links e imagem na notificação.
Push usa Firebase Cloud Messaging (FCM) nos três backends. O FCM entrega no device; seu backend decide quando e pra quem enviar.
| Backend | Como dispara |
|---|---|
| Firebase | Cloud Function ao inserir em users/{uid}/notifications/{id} |
| Supabase | Edge Function via webhook na tabela notifications |
| API REST | Seu servidor chama FCM via HTTP |
Implementação
Push usa FCM nos três backends. No modo Rápido:
- Firebase backend: push já vem no preset
- Supabase / API: no Rápido a CLI pergunta se quer push. Se sim, cria/liga companion Firebase (FCM). Se não, fica sem companion; dá pra ligar depois com Advanced,
--pushno MCP, oukasy add notifications
O kasy new interativo configura o que for possível na hora. Credenciais adiadas no Rápido: Android funciona sem passo extra no emulador. iOS precisa de uma APNs Key (todos os backends). Supabase + API REST precisam da service account do Firebase quando o módulo push estiver ligado.
Pelo MCP: depois do setup, peça "checa a configuração de push do meu projeto" (check_project) ou "checa e corrige o push" (check_project com fix). Veja MCP do Kasy.
iOS: APNs Key (todos os backends)
A APNs Key só existe no Apple Developer Portal e precisa de upload no Firebase Console. Uma chave serve para todos os apps do mesmo Team ID.
1. Criar a chave no Apple Developer Portal
- Acesse developer.apple.com → Keys → "+"
- Dê um nome (ex.:
Firebase APNs Key) - Ative Apple Push Notifications service (APNs)
- Clique em Continue → Register
- Baixe o
.p8: só pode baixar uma vez; guarde em lugar seguro - Anote o Key ID e o Team ID (canto superior direito do portal)
Dica: ative também Sign In with Apple na mesma chave. Assim você tem um único .p8 para push e login Apple.
2. Upload no Firebase Console
- Firebase Console → Cloud Messaging → seção Apps Apple
- Selecione o app iOS → clique em Fazer upload
- Selecione o
.p8, preencha Key ID e Team ID - Repita para Desenvolvimento e Produção (mesmo arquivo)

3. Verificar
Console Admin → Ferramentas → Enviar notificação de teste. No iOS, o app precisa estar com permissão de push concedida.
kasy check # diagnóstico: secrets, edge functions, IAM
kasy check --fix # corrige automaticamente
kasy deploy # re-deploy das functionsPelo MCP: "verifica o projeto" (check_project, com fix opcional), "faz o deploy do backend" (deploy_backend).
Supabase e API REST: chave do Firebase Service Account
No Firebase backend, push funciona "sem chave" porque o servidor usa as credenciais padrão do projeto Google Cloud (ADC). No Supabase e na API REST, o servidor é externo ao Firebase: você precisa gerar e cadastrar uma chave JSON.
1. Gerar a chave no Firebase Console
- Abra o Firebase Console → seu projeto
- Configurações do projeto → Service accounts
- Gerar nova chave privada → JSON → Criar
- Guarde o arquivo (é um JSON de ~1 KB com
type,project_id,private_keyetc.)

2. Cadastrar no backend
| Backend | Como cadastrar |
|---|---|
| Supabase | O kasy deploy cria a service account e grava FIREBASE_SERVICE_ACCOUNT_JSON e FIREBASE_PROJECT_ID. Manual depois: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='<conteúdo do JSON>' e supabase secrets set FIREBASE_PROJECT_ID=seu-id |
| API REST | Você carrega o JSON no seu servidor e usa a SDK do Firebase Admin (Node, Python, Go etc.) para chamar firebase-admin.messaging().send() |
Nunca coloque a chave JSON no app Flutter ou no .env do cliente. Ela vai SÓ no servidor.
Informações
Enviar notificações
Para um usuário: Firebase (Firestore)
// users/{userId}/notifications/{id}
{
title: "Título",
body: "Corpo da mensagem",
type: "OTHER",
notify_user: true,
}Para um usuário: Supabase (SQL)
INSERT INTO public.notifications (user_id, title, body, type)
VALUES ('uuid-do-usuario', 'Título', 'Corpo', 'OTHER');Para todos os usuários: Supabase
INSERT INTO public.notifications (user_id, title, body, type)
SELECT DISTINCT ON (d.user_id) d.user_id,
'Título', 'Corpo', 'OTHER'
FROM public.devices d
ORDER BY d.user_id, d.creation_date DESC;Pelo app (Console Admin)
Settings → Admin → Ferramentas → Enviar notificação. Permite enviar para e-mail específico ou para todos, com imagem e tela de destino.
Deep link (navegar ao tocar)
O campo data controla para onde o app navega:
data | Comportamento ao tocar |
|---|---|
| vazio | Abre a lista de Notificações |
{"route": "/premium"} | Navega para a tela interna |
{"url": "https://..."} + type: LINK | Abre no browser externo |
O campo route aceita qualquer caminho do GoRouter. Funciona em qualquer estado do app (foreground, background, fechado).
Exemplos:
-- Leva para a tela de assinatura
INSERT INTO public.notifications (user_id, title, body, type, data)
VALUES ('uuid', 'Oferta!', 'Toque para ver.', 'OTHER', '{"route": "/premium"}');
-- Abre link externo
INSERT INTO public.notifications (user_id, title, body, type, data)
VALUES ('uuid', 'Novidade', 'Veja no site.', 'LINK', '{"url": "https://seusite.com/novidade"}');Deep link dinâmico (ex.: abrir um post específico)
Mesma ideia, mas com parâmetro na rota:
- Crie a rota em
router.dart:/post/:id - Envie
{"route": "/post/123"}no campodata
Cada notificação aponta para um conteúdo diferente, igual ao comportamento de Twitter e Instagram. A engrenagem (navegação, back stack, todos os estados do app) já vem pronta.
Imagem na notificação
Inclua image_url com uma URL pública JPEG/PNG:
// Firebase
{
title: "Oferta!",
body: "Toque para ver.",
image_url: "https://exemplo.com/imagem.jpg",
type: "OTHER",
notify_user: true,
}-- Supabase
INSERT INTO public.notifications (user_id, title, body, type, image_url)
VALUES ('uuid', 'Oferta!', 'Toque para ver.', 'OTHER', 'https://exemplo.com/imagem.jpg');Aparece como thumbnail no banner do sistema (iOS precisa de UNNotificationServiceExtension, que já vem no projeto em ios/NotificationService/).
Comportamento por estado do app
| Estado | O que acontece |
|---|---|
| Foreground (app aberto) | Banner local + notificação salva na lista in-app |
| Background (minimizado) | Banner do sistema operacional |
| Fechado | Banner do SO; ao tocar abre o app na tela certa |
Por que o Kasy envia a notificação pronta (e não só dados)
O servidor manda a notificação já com título e texto (notification), e o sistema operacional a mostra, mesmo com o app fechado. É o que o mercado usa quando a prioridade é a notificação chegar.
Enviar só dados ("data-only") e deixar o app decidir parece mais flexível, mas no iOS esse tipo de mensagem é tratado como silenciosa: o sistema pode atrasar ou descartar, e não acorda um app fechado. Trocar a notificação pronta por data-only deixaria de entregar parte das notificações. Por isso o Kasy não faz isso por padrão.
O que o app não pode fazer sozinho (horário silencioso, tipos desligados pelo usuário) é filtrado no servidor, antes de enviar, e vale igual no iOS, no Android e na web. Isso está no roadmap do kit (preferências de notificação). Até lá, sua regra de "quem recebe o quê" fica no código que chama o envio.
Observações
- Emulador Android precisa de conta Google configurada no emulador para gerar token FCM válido.
- iOS com debugger conectado pode bloquear push em background. Pressione
dno terminal para desconectar o debugger mantendo o app rodando. - A chave
.p8só pode ser baixada uma vez: guarde bem.
Atualizado em 03/11/2026

