Diretor que abre WhatsApp toda manhã e quer ver os números do dia anterior. Equipe comercial em grupo de WhatsApp que precisa de update semanal. Sócio que quer ler relatório no celular sem entrar no Syncro. Pra esses casos, o Syncro tem Relatórios Automáticos (/relatorios/assinaturas): você agenda frequência + destino + filtros + mensagem, e sistema envia snapshot via WhatsApp com link público. Esse artigo cobre como criar, gerenciar e os bastidores.
Pré-requisitos
- Permissão admin ou manager.
- WhatsApp via QR Code conectado (Cloud API limita target a contact/self — não suporta listar grupos).
- Pelo menos 1 número configurado.
Acessar assinaturas
- Menu lateral → Relatórios → Assinaturas (ou rota
/relatorios/assinaturas). - Página mostra grid de cards com assinaturas cadastradas.
- Botão Nova assinatura no canto superior direito.
Card de cada assinatura
Cada card mostra:
- Nome + ícone.
- Destino (badge: Grupo / Contato / Próprio número).
- Frequência (badge: Diário / Semanal / etc).
- Próximo envio: "Em 3 horas" ou "Daqui a 2 dias".
- Último envio: timestamp ou "Nunca enviado".
- Total enviado: contador.
- Toggle ativar/pausar.
- Menu 3 pontos: Enviar agora / Editar / Excluir.
Se houve erro no último envio: badge vermelho com last_error.
Wizard de criação (3 passos)
Botão Nova assinatura abre wizard fullscreen estilo AI Agent.
Passo 1 — Conteúdo
Define o que vai no relatório:
- Nome (obrigatório): identificador interno. Ex: "Resumo Diário Comercial", "Update Semanal Suporte".
- Período do relatório (
filters.range): last_7_days— últimos 7 dias.last_14_days— últimos 14 dias.last_30_days(default) — últimos 30 dias.this_month— mês corrente.last_month— mês anterior.this_quarter— trimestre corrente.- Pipeline (opcional): dropdown — filtra dados desse pipeline. Vazio = todos.
- Responsável (opcional): dropdown — só dados desse user. Vazio = todos.
Passo 2 — Destino
Pra onde o relatório vai:
- Instância WhatsApp (obrigatório): dropdown lista instâncias QR Code conectadas.
⚠️ Atenção: Cloud API não suporta listar grupos (limitação Meta API). Se sua única instância é Cloud, target=
groupnão funciona — sócontactouself.
- Tipo de destino:
Grupo
3 cards visuais:
- Grupo — selecione um grupo existente.
- Contato — número específico.
- Meu número — o próprio número da instância.
Tipo "Grupo"
- Dropdown de grupos carregado via AJAX (
GET /api/whatsapp/groups?instance_id=X). - Cache 120s — depois de selecionar instância, espera ~1s pra dropdown popular.
- Mostra: nome do grupo + qtd de participantes.
- Salva como
target_chat_id = "{groupId}@g.us".
Tipo "Contato"
- Input de telefone com formato E.164 (ex:
+5511999999999). - Sistema usa SmartSender com retry: tenta com nono dígito, sem nono, variantes DDI.
Tipo "Meu número"
- Sem input — usa
phone_numberda instância automaticamente. - Útil pra você receber sozinho o relatório.
Passo 3 — Agendamento
Quando enviar e como customizar:
- Mensagem (obrigatório, max 2000 chars): texto que vai junto do link. Suporta variáveis interpoladas (ver abaixo).
- Frequência (4 opções):
Daily — todo dia
- Horário (
time_of_day): formatoHH:MM(ex:09:00). - Envia diariamente nesse horário no timezone do user (default
America/Sao_Paulo).
Weekly — semanal
- Dia da semana: dropdown 1=Segunda a 7=Domingo.
- Horário:
HH:MM. - Envia semanalmente no dia escolhido.
Biweekly — quinzenal
- Dia da semana: como weekly.
- Horário:
HH:MM. - Envia a cada 2 semanas.
Monthly — mensal
- Dia do mês: dropdown 1-28 (limitado pra evitar bug fevereiro).
- Horário:
HH:MM. - Envia mensalmente no dia escolhido.
⚠️ Atenção: dia do mês limitado a 1-28. Pra "último dia do mês", use 28.
- Senha do link (opcional, 4-100 chars): protege link público com senha. Cliente precisa digitar pra ver.
- Validade do link (
expires_days, default 30): após esse período, link expira. Range 1-365.
Variáveis interpoláveis na mensagem
Sistema substitui {{variavel}} por valor real ao enviar:
| Variável | O que vira |
|---|---|
{{leads}} |
Total de leads do período |
{{vendas}} |
Total de vendas |
{{receita}} |
Receita total formatada (R$ 12.345) |
{{ticket_medio}} |
Ticket médio |
{{conversao}} |
Taxa de conversão (%) |
{{conversas}} |
Conversas WhatsApp |
{{leads_perdidos}} |
Leads perdidos |
{{delta_leads}} |
Variação leads vs período anterior (+18%) |
{{delta_receita}} |
Variação receita |
{{top_origem}} |
Origem que mais gerou leads |
{{top_vendedor}} |
Vendedor com mais vendas |
{{top_produto}} |
Produto mais vendido |
{{top_utm}} |
UTM campaign top |
{{empresa}} |
Nome do tenant |
{{periodo}} |
Texto do período (ex: "01/04 - 30/04") |
{{data}} |
Data atual (dd/mm/yyyy) |
{{link}} |
Link público (auto-anexado se não usar) |
Templates prontos (presets)
UI tem 6 presets clicáveis:
- Resumo semanal — formato de update pra grupo.
- Executivo — pra diretoria.
- Comercial — motivacional pra vendedores.
- Alerta — alerta de performance ruim.
- Minimalista — versão reduzida.
- WhatsApp — foco em métricas WhatsApp.
Clica → preenche textarea com template. Edite à vontade.
Salvar e ativar
- Após preencher 3 steps, clique em Criar assinatura.
- Sistema:
- Cria
ReportSubscriptionno banco. - Calcula
next_run_atviaScheduleCalculator. - Marca
is_active=true.
- Toast: "Assinatura criada!".
- Card aparece no grid.
Como funciona o envio (cron)
Comando reports:send-subscriptions roda a cada 5 minutos:
- Busca
ReportSubscription WHERE is_active=true AND next_run_at <= now. - Pra cada subscription:
- WhatsappTargetResolver valida instância + resolve
chatId. - ReportSnapshotBuilder gera
GeneratedReportcom dados congelados em JSON + senha hash + expires_at. - Monta mensagem interpolando variáveis.
- Anexa link público (
{{link}}ou auto no final). - Envia via
WhatsappServiceFactory::for($instance)->sendText. - Atualiza:
last_sent_at = now,sent_count++, recalculanext_run_at.
- Em falha:
last_errorpreenchido.- Não recalcula
next_run_at(evita loop de retry). - Próximo cron tenta de novo.
Botões de ação
Cada card tem:
Enviar agora
POST /relatorios/assinaturas/{id}/enviar.
- Dispara envio imediato.
- NÃO altera
next_run_at— agenda continua intocada. - Útil pra testar nova assinatura.
Pausar / Reativar
Toggle do card.
- Pausar:
is_active=false. Cron ignora. Card ganha badge "Pausado". - Reativar:
is_active=true.next_run_atrecalcula pra próxima ocorrência.
Editar
Reabre wizard 3-step com dados preenchidos.
Excluir
Confirma e deleta. Não afeta GeneratedReports já enviados — links públicos continuam válidos.
Snapshot de relatório
Cada envio gera GeneratedReport:
- Dados congelados em
snapshot_jsonno momento da geração. - Não muda se lead/sale for deletado depois.
- Link público
/r/{hash}(URL com hash 20 chars). - Senha se você configurou (Hash::check).
- Expira após
expires_days.
Veja Relatório público com link.
Casos práticos
Diretor — Update diário
- Frequência: Daily 08:00.
- Destino: Meu número.
- Período:
last_7_days. - Mensagem:
Bom dia! 📊
Update últimos 7 dias:
Leads: {{leads}} ({{delta_leads}})
Vendas: {{vendas}}
Receita: {{receita}} ({{delta_receita}})
Conversão: {{conversao}}
Top origem: {{top_origem}}
Detalhes: {{link}}
Equipe Comercial — Update semanal
- Frequência: Weekly Segunda 09:00.
- Destino: Grupo "Comercial".
- Período:
last_7_days. - Mensagem:
⚡ Resumo semanal:
• {{leads}} leads
• {{vendas}} vendas fechadas
• R$ {{receita}}
• Top vendedor: {{top_vendedor}} 🏆
Detalhes: {{link}}
CFO — Mensal pra contabilidade
- Frequência: Monthly Dia 1 09:00.
- Destino: Contato +5511999999999 (CFO).
- Período:
last_month. - Senha: Sim (PIN 4 dígitos).
- Validade: 90 dias.
- Mensagem:
Relatório mensal {{periodo}}:
Receita: {{receita}}
Vendas: {{vendas}}
Senha: 1234
Link: {{link}}
Erros comuns
"Group dropdown vazio"
- Cloud API não suporta listar grupos.
- QR Code pode levar alguns segundos pra carregar (cache 120s).
- Confira que instância tem grupos que você participa.
"Não recebo o relatório"
- Verifique cron
reports:send-subscriptionsrodando (super_admin pode ver). - Última
next_run_atjá passou? is_active=true?last_errorpreenchido? Mostra causa.
"Link público pede senha mesmo sem ter configurado"
Bug raro — verifique se password ficou preenchido por engano. Edite e limpe.
"Variáveis aparecem como {{leads}} literal na mensagem"
Sistema interpola antes do envio. Se ficou literal, problema de execução do MessageInterpolator. Contate suporte.
"Frequência mensal mudou de dia inesperadamente"
Limite 1-28 garante consistência. Se você selecionou 28, sempre dia 28 (mesmo fevereiro 28).
Limites
- Sem limite oficial de assinaturas por tenant.
- Mas cron processa uma a cada vez — muitas assinaturas no mesmo horário podem causar atraso de minutos.
💡 Dica: distribua horários (08:00, 08:15, 08:30) pra escalar.
Próximos passos
- Pra entender link público em detalhes, veja Relatório público com link.
- Pra exportar dados pra Excel, veja Exportar leads.