Acompanhar o churn com os webhooks do Lemon Squeezy
Que eventos de webhook do Lemon Squeezy marcam um cancelamento, uma expiração, um pagamento falhado ou uma recuperação, e como criar um registo de churn.
Se vende subscrições através do Lemon Squeezy, todos os sinais de churn de que precisa passam pelos seus webhooks: cancelamentos, expirações, renovações falhadas, recuperações, pausas. A parte difícil não é recebê-los. É decidir que evento significa o quê, e registá-los de forma a que os seus números de churn ainda batam certo daqui a seis meses.
Este guia faz corresponder os eventos de subscrição do Lemon Squeezy aos conceitos de churn, mostra como guardá-los e lista os detalhes de entrega que fazem falhar os handlers ingénuos. Limita-se à documentação do próprio Lemon Squeezy: os tipos de eventos de webhook, a página de pedidos de webhook, a assinatura dos pedidos, o guia de sincronização com webhooks e a referência do objeto Subscription (todos consultados em novembro de 2026).
Os eventos de subscrição
A página de tipos de eventos do Lemon Squeezy lista estes eventos de subscrição:
| Evento | O que o desencadeia segundo o Lemon Squeezy | Significado para o churn |
|---|---|---|
subscription_created |
Uma nova subscrição | Cliente novo (ou que regressa) |
subscription_updated |
Qualquer alteração depois do pagamento inicial | Usar para sincronizar o estado |
subscription_cancelled |
Cancelada pelo cliente ou pelo dono da loja; entra num período de tolerância até à próxima data de faturação | Churn agendado, ainda não aconteceu |
subscription_resumed |
Retomada depois de cancelada | Churn agendado revertido |
subscription_expired |
Terminada depois de cancelada, ou quando o dunning foi concluído para subscrições past_due |
O churn aconteceu |
subscription_paused |
Cobrança em pausa | Não é churn; acompanhar à parte |
subscription_unpaused |
Cobrança retomada | Fim da pausa |
subscription_payment_success |
Um pagamento bem-sucedido | Receita |
subscription_payment_failed |
Um pagamento de renovação falhou | Risco de churn involuntário |
subscription_payment_recovered |
Um pagamento bem-sucedido depois de um falhado | Risco resolvido |
subscription_payment_refunded |
Um pagamento reembolsado | Ajuste de receita |
Dois destes merecem um olhar mais atento.
Cancelado não é perdido
subscription_cancelled dispara quando o cliente clica em cancelar, mas a subscrição continua a funcionar até ends_at. Durante esse período de tolerância pode ser retomada, o que envia subscription_resumed. Se contar o churn em subscription_cancelled, cada subscrição retomada passa a ser um falso churn, e a sua data de churn fica desfasada até um período de faturação inteiro.
Conte o churn em subscription_expired. Mantenha subscription_cancelled como uma métrica antecipada à parte: “cancelamentos agendados este mês”.
Um evento, dois tipos de churn
subscription_expired dispara por duas razões muito diferentes: um cliente que cancelou e chegou a ends_at (churn voluntário), e uma subscrição que passou pelo dunning depois de pagamentos falhados sem recuperar (churn involuntário). O nome do evento não lhe diz qual.
Para os separar, veja o que veio antes. Se o seu registo tem um subscription_cancelled para essa subscrição e nenhum subscription_resumed depois, é voluntário. Se tem eventos subscription_payment_failed e nenhuma recuperação, é involuntário. Também pode ler o estado da subscrição quando recebe o evento: a referência do objeto Subscription mostra um booleano cancelled ao lado de status.
O churn voluntário e o involuntário pedem soluções diferentes, por isso esta separação é a coisa mais útil que o seu registo lhe pode dar.
Como são os pedidos
Segundo a página de pedidos de webhook:
- Cada pedido é um
POSTcom um corpo JSON:API: o recurso relacionado com o evento (uma subscrição para a maioria dos eventos de subscrição, uma subscription invoice para os eventos de pagamento). - O cabeçalho
X-Event-Nametraz o nome do evento. - O cabeçalho
X-Signaturetraz a assinatura. - O seu endpoint tem de devolver
200. Qualquer outro estado é tentado de novo até mais três vezes com espera exponencial (a documentação dá 5, 25 e 125 segundos como exemplo), depois do que o pedido é considerado falhado.
A página de definições de webhooks no seu painel regista as entregas recentes com os seus payloads e permite reenviá-las. É a sua rede de segurança se o seu endpoint esteve em baixo.
Verificar a assinatura
A assinatura dos pedidos explica o esquema: define um segredo de assinatura ao criar o webhook (6 a 40 caracteres), e o Lemon Squeezy calcula com ele um digest HMAC-SHA256 em hexadecimal do corpo do pedido. Recalcule o digest sobre o corpo bruto, não sobre JSON reserializado, e compare com uma função de tempo constante. Rejeite tudo o que não corresponder.
Os eventos de pagamento trazem faturas
Os eventos subscription_payment_* trazem um objeto subscription invoice, não a subscrição. Este referencia a subscrição, por isso guarde esse ID e, se precisar do estado, obtenha a subscrição.
Construir um registo de churn passo a passo
O objetivo é uma tabela só de acrescento com o que aconteceu a cada subscrição, a partir da qual se pode recalcular qualquer métrica de churn.
- Crie um endpoint para todos os eventos de subscrição. Subscreva-o aos eventos da tabela acima. O guia de sincronização do Lemon Squeezy nota que
subscription_updatedcobre todas as alterações, por isso pode subscrever só esse se apenas quiser o estado. Para acompanhar o churn, os eventos específicos são mais fáceis de interpretar, por isso fique com ambos. - Verifique e depois guarde o payload bruto. Escreva o nome do evento, o ID da subscrição, o ID do cliente, a data e hora e o JSON bruto antes de fazer qualquer outra coisa.
- Elimine duplicados. As novas tentativas e os reenvios manuais fazem com que o mesmo evento possa chegar duas vezes. A documentação que usámos não descreve um ID de evento único no pedido, por isso construa a sua própria chave a partir do nome do evento, do ID do recurso e do
updated_atdo recurso, e ignore as repetições. - Responda depressa. Devolva
200assim que o evento está guardado e processe-o numa tarefa em segundo plano. Um handler lento que excede o tempo desencadeia novas tentativas. - Derive, não sobrescreva. Mantenha o registo imutável. Calcule o “estado atual” e as contagens de churn a partir dele, para que um bug na sua lógica possa ser corrigido voltando a reproduzir o registo.
- Reconcilie de vez em quando. Uma vez por semana, liste as subscrições através da API e compare os estados com o que o seu registo diz. Qualquer diferença significa um evento perdido.
As métricas que pode calcular
Com esse registo, estas são diretas:
- Taxa de churn de clientes num mês: subscrições que expiraram durante o mês, divididas pelas subscrições ativas no início do mês.
- Parte voluntária vs involuntária: expirações separadas pela regra acima.
- Cancelamentos agendados: eventos
subscription_cancelledno mês, um indicador antecipado do churn do mês seguinte. - Recuperações no período de tolerância: subscrições canceladas seguidas de
subscription_resumed. - Taxa de recuperação de pagamentos: subscrições com um
subscription_payment_recovereddivididas pelas subscrições com umsubscription_payment_failedno mesmo período. - Parte em pausa: subscrições atualmente
paused. Apresente-as à parte; não são pagantes ativos nem churn.
Defina cada métrica uma vez, por escrito, e mantenha a definição estável. Uma taxa de churn só é útil comparada consigo própria ao longo do tempo.
Testar antes de confiar
O modo de teste do Lemon Squeezy pode simular eventos de webhook para subscrições. Passe cada ciclo de vida por ele: criar, cancelar, retomar, cancelar de novo e deixar expirar; um pagamento falhado que recupera; um que não recupera. Verifique que o seu registo e as suas métricas correspondem ao que espera em cada passo.
Fazer isto com a NoChurn
O Lemon Squeezy continua a ser a fonte de verdade para as subscrições e os pagamentos; a NoChurn não os altera. A NoChurn subscreve os seus webhooks do Lemon Squeezy, guarda e elimina duplicados nos eventos, e separa por si o churn voluntário do involuntário. Por cima disso acrescenta um churn score de 0 a 100 por cliente, os dados próprios que envia por API e as respostas do fluxo de cancelamento que explicam porque é que as pessoas saem. As disputas, que o Lemon Squeezy trata enquanto merchant of record, são mostradas só em leitura. Veja NoChurn + Lemon Squeezy.