# Assinaturas, MRR e LTV

Estados recorrentes observados e métricas com elegibilidade e histórico explícitos.

## Escopo da leitura

Este módulo mede contratos dos seus clientes. Registrar um estado não cria uma assinatura no gateway nem cobra alguém. O billing da Pulsant continua Pix avulso com renovação manual. A API genérica de estados está implementada; a cobertura nativa por provedor é registrada separadamente e não está concluída para os oito gateways.


## Assinaturas Asaas

Habilite SUBSCRIPTION_CREATED, SUBSCRIPTION_UPDATED, SUBSCRIPTION_INACTIVATED e SUBSCRIPTION_DELETED. Os eventos de Split disabled, divergence block e block finished também são registrados: bloqueio fica em espera; fim do bloqueio usa o estado informado. INACTIVE é pausa reversível, EXPIRED é expiração e remoção é cancelamento confirmado. PAYMENT_CONFIRMED/PAYMENT_RECEIVED continuam no fluxo de cobrança; receber estado de assinatura não registra receita nem consome franquia. Use um token exclusivo no header asaas-access-token; ele autentica a entrega, mas não é uma assinatura criptográfica do corpo. Não reutilize a chave de API como token.


## Horários e limites do Asaas

Os exemplos oficiais trazem dateCreated sem offset. A operação deve confirmar o fuso desses eventos e definir ASAAS_WEBHOOK_TIMEZONE na API e no worker, como timezone IANA. A Pulsant não presume o fuso do computador nem o timezone do site. Sem configuração, o recebimento fica preservado com diagnóstico para reprocessar; datas ISO com offset explícito dispensam essa configuração. Horários inexistentes ou ambíguos em transições de horário de verão exigem confirmação na origem, sem escolher um offset silenciosamente. A configuração atual é por instalação: contas com fusos diferentes precisam de suporte específico antes da ativação. nextDueDate é vencimento, não o período atual confirmado. MRR/ARR nativos Asaas permanecem indisponíveis até a medição recorrente ser completada; valor e ciclo isolados não fabricam esse período. externalReference pode conter JSON com pulsant_subscription_id e pulsant_external_user_id opacos; nomes, e-mails e referências livres não identificam automaticamente um cliente.


## Assinaturas Stripe

Na conexão Stripe, habilite customer.subscription.created, updated, deleted, paused, resumed e trial_will_end. O webhook assinado conserva o estado e a data de cada evento; entregas atrasadas não substituem estados mais recentes. Preços recorrentes fixos por unidade usam quantidade e intervalo, com períodos nos itens ou no formato legado da assinatura. Cancelamento agendado permanece ativo até o encerramento confirmado. Metadados opcionais pulsant_subscription_id e pulsant_external_user_id permitem vínculo determinístico; não envie nomes ou e-mails. Não é preciso consultar o estado atual para substituir o histórico de um webhook.


## Cobertura da Stripe

O MRR nativo exige lista completa de até 20 itens, moeda única, preço fixo inteiro, impostos externos conhecidos e período confirmado. Descontos, preço variável/em faixas, impostos incluídos ou não resolvidos, quantidade transformada, valores fracionários e atualizações pendentes têm medição indisponível explícita, sem somar apenas parte do contrato. As atualizações da assinatura não registram pagamentos nem consomem unidades como novas vendas. Esta cobertura passou com payloads sintéticos e assinatura realista; a execução externa em sandbox foi cancelada.


## Assinaturas Polar e Paddle

Os adaptadores registram snapshots assinados dos eventos de assinatura, sem trocar seu histórico por uma consulta atual. Polar usa valor e preço fixo único correspondentes, intervalo, período e imposto externo explícito; modelos por quantidade/uso, desconto ou imposto não resolvido ficam fora do MRR. Inclui o evento de ciclo e a assinatura que migra de outro provider, sem importar os pagamentos anteriores. Paddle multiplica quantidade de itens recorrentes, exclui itens avulsos e usa o período confirmado; preço por país, desconto e imposto dependente da conta/localidade exigem medição posterior. Cancelamento agendado não encerra o contrato antecipadamente; atraso e pausa retiram o contrato do MRR enquanto persistirem. Configure o destino de produção do provedor; nesses payloads a conexão determina a origem dos dados. Contratos e fluxo HTTP/PostgreSQL passaram com fixtures sintéticas; Mercado Pago mede MRR quando snapshot canônico da assinatura, plano individual, valor, moeda, frequência e período atual coincidem; alterações de planos conhecidos são reconciliadas em páginas. Lemon Squeezy mede contratos fixos elegíveis após conferir item, preço, fatura e ciclo atual na API canônica. Asaas mantém estados, mas MRR fica indisponível sem início do período atual confirmado. Woovi registra estados e parcelas; o esquema disponível não informa intervalo recorrente, então a Pulsant não inventa MRR.

- [Polar subscription.updated](https://polar.sh/docs/api-reference/2026-10/subscription_updated)
- [Polar subscription.migrated](https://polar.sh/docs/api-reference/2026-10/subscription_migrated)


## Registrar pelo servidor

Use POST /v1/workspaces/{workspace}/sites/{site}/subscriptions com chave privada limitada ao site e escopo integrations:write. O SDK local do monorepo oferece subscription(); ele ainda não é anunciado como pacote npm publicado. eventId deve ser estável em retries e externalId identifica o contrato na origem. logicalId opcional permite um identificador explícito de negócio; não associe contratos por coincidência de e-mail, IP ou horário. Eventos anteriores ao início da conexão/credencial e datas futuras além da tolerância são recusados.

```
const event = {
  eventId: 'event_subscription_2026_10',
  externalId: 'subscription_123',
  environment: 'production',
  status: 'active',
  occurredAt: new Date().toISOString(),
  measurement: 'available',
  items: [{ amountMinor: '120000', currency: 'BRL', interval: 'year', intervalCount: 1 }],
  periodStart: '2026-10-01T00:00:00Z',
  periodEnd: '2027-10-01T00:00:00Z',
  cancelAtPeriodEnd: false
};
// Com a instância server-side do SDK local já configurada:
await pulsant.subscription(event);
```

## Estados de assinatura Lemon Squeezy

Habilite subscription_created, subscription_updated, subscription_cancelled, subscription_resumed, subscription_expired, subscription_paused e subscription_unpaused no destino de produção. O estado on_trial vira avaliação; cancelled permanece ativo com cancelamento agendado durante a carência, e expired registra encerramento confirmado. Conservamos a data updated_at e os estados fora de ordem não substituem os mais recentes. O webhook sozinho não confirma preço efetivo ou ciclo atual. Com a chave de API, a Pulsant valida assinatura canônica, item fixo único, preço, fatura atual e período vigente; só esse conjunto elegível entra no MRR/ARR. Descontos, estornos, múltiplos itens, uso variável ou divergências mantêm a medição indisponível; nenhuma taxa é inferida.


## Pedido inicial e renovações Lemon

subscription_created vincula order_id à assinatura de forma durável e isolada por conexão. Pedido e assinatura podem chegar em qualquer ordem. O vínculo e o estado da assinatura são confirmados na mesma transação; conflito é recusado e fica no diagnóstico. Quando o vínculo inicial já é conhecido, uma renovação recebida antes do pedido confirmado fica pendente de processamento, sem consumo de unidade, para reprocessamento. Os eventos de sucesso e recuperação usam o mesmo ID da invoice; a invoice inicial não duplica a venda registrada pelo pedido. A aquisição da renovação considera somente pagamentos anteriores da mesma conexão/provedor/ambiente. Sem vínculo ou origem confiável, não há inferência por e-mail ou horário nem reatribuição retroativa automática.


## Assinaturas Dodo Payments

Habilite os eventos de assinatura no destino de produção, incluindo active, updated, past_due, on_hold, paused, unpaused, renewed, plan_changed, update_payment_method, cancelled, failed e expired. Preservamos espera, pausa, falha, pendência e expiração como estados distintos. Para MRR fixo, a medição inicial exige quantidade 1, carrinhos completos e vazios de adicionais/uso/créditos, cobrança programada, valor inteiro conhecido, moeda, impostos externos, período válido e, para valores positivos, forma de pagamento confirmada. Quantidades maiores, descontos e modelos especiais ficam com motivo de medição indisponível, sem somar parte do contrato.


## Avaliação, renovação e expiração na Dodo

subscription.active também pode ocorrer na autorização inicial de uma avaliação, antes da cobrança recorrente. Quando trial_period_days for positivo, somente um snapshot renewed fornece a confirmação explícita usada nesta cobertura; outras atualizações sem essa confirmação ficam com medição indisponível. A frequência de pagamento normaliza o MRR; a duração total do contrato não é usada como frequência. Renovação de contrato não cria uma transação: o pagamento confirmado é registrado pelo evento payment.succeeded. Expiração encerra o MRR e entra no churn observado, separada dos cancelamentos. Metadados opcionais pulsant_external_user_id e pulsant_subscription_id permitem associação explícita; dados pessoais aninhados do cliente não entram no snapshot recorrente.


## Preço e disponibilidade

Cada amountMinor é o total recorrente do item no período, já incluindo quantidade e descontos recorrentes conhecidos, antes de impostos. Envie inteiro em string e moeda original; uma assinatura usa uma única moeda e até 20 itens. Intervalos day/week/month/year aceitam contagem de 1 a 120. Sem preço/período suficientes, envie measurement: unavailable, items: [] e unavailableReason, por exemplo missing_price. Preços variáveis ou descontos desconhecidos não viram zero. Não registre um pagamento confirmado apenas por existir um contrato ativo.


## MRR e ARR

Somente estados ativos, com preço conhecido, período vigente e ordem confiável entram no MRR. Trial, atraso, pausa e medição indisponível ficam fora. Meses dividem pelo intervalo; anos dividem por 12 vezes o intervalo; semanas usam 52/12 e dias 365/12. Somamos frações exatas antes de arredondar em unidades mínimas. ARR multiplica a fração mensal exata por 12, sem multiplicar um MRR já arredondado. Moedas permanecem separadas e contagens são por assinatura, não por pessoa. MRR/ARR não equivalem a caixa recebido ou garantia de receita futura.


## Ordem, duplicidade e cancelamento

O mesmo eventId com estado, entidade ou data diferente é recusado; retries iguais não repetem efeito nem contador. Estados atrasados são preservados no histórico sem sobrescrever o mais recente. Estados diferentes com o mesmo instante tornam a leitura ambígua, excluída da medição até observar um estado mais recente confirmado. cancelAtPeriodEnd informa agendamento; ele não muda active para canceled antecipadamente. Valores ausentes e períodos sem atualização permanecem explícitos.


## Churn observado

A base contém assinaturas ativas elegíveis com valor recorrente positivo no início do período; o numerador é a parte dessa base que está cancelada no fim. Reativações até o fim não contam como canceladas. Não é churn de pessoas nem churn de receita. Sem base observada o percentual fica indisponível; contratos sem preço e estados ambíguos sinalizam leitura parcial. Não inferimos o estado que uma assinatura tinha antes da conexão.


## LTV realizado parcial

É a média de pagamentos confirmados menos ajustes observados, por cliente identificado e moeda, em até 366 dias até o fim do recorte. Ajustes posteriores ao ponto consultado não são antecipados. Pagamentos sem identidade ficam fora da média e sua quantidade é mostrada. Sem clientes identificados não há valor; amostras pequenas e histórico parcial são sinalizados. Não é uma projeção da vida útil e não fabrica uma coorte completa. Taxas e impostos ausentes não são estimados.


## Consulta e atualização

GET no mesmo endpoint retorna métricas, cobertura e lista de 20 assinaturas por página. Preserva ambiente, período e moeda, com datas no timezone do site. O recorte padrão é de 30 dias para churn; LTV explicita sua janela observada. Filtros de tráfego ainda não filtram contratos. A interface recebe invalidações financeiras SSE, agrupa avisos e refaz a leitura autorizada; o stream não transporta valores ou identidades. Após reconectar ela consulta o estado atual novamente. PostgreSQL é a fonte financeira.


## Limites e evidências

Atualizações de assinatura são técnicas e não debitam novamente a unidade do pagamento. Limite operacional padrão de 10.000 atualizações novas por workspace/dia UTC, configurável por SUBSCRIPTION_DAILY_UPDATES; retries aceitos não consomem esse contador. A consulta tem teto técnico de 10.000 contratos observados no recorte. O fluxo SDK/HTTP/PostgreSQL/SSE e as regras monetárias passaram com dados sintéticos; isso não comprova validação financeira externa. Consulte a matriz de provedores antes de tratar uma conexão como fonte de preço recorrente disponível.

