No começo, cobrança parece uma tela.
O usuário escolhe um plano, informa o cartão e recebe acesso. Um endpoint cria a assinatura. Outro webhook marca a conta como ativa. Está resolvido.
Até o produto ganhar mais de um preço.
A primeira versão mistura quatro problemas
O fluxo de compra costuma juntar coisas diferentes no mesmo bloco de código:
- Preço: quanto cobrar, em qual ciclo e por qual unidade.
- Medição: o que o cliente consumiu durante o período.
- Pagamento: qual provedor processa Pix, boleto ou cartão.
- Acesso: o que o produto libera depois da confirmação.
Na primeira versão, as quatro decisões cabem num if. O plano está numa tabela, o status do pagamento vira uma coluna e o acesso é uma condição no middleware.
Isso não está errado. É só uma arquitetura com prazo de validade.
O crescimento aparece nas exceções
O problema raramente é criar a primeira assinatura. É decidir o que acontece quando:
- o cartão falha no meio de um ciclo;
- o cliente muda de plano depois de consumir parte da franquia;
- o mesmo evento de uso chega duas vezes;
- o pagamento confirma, mas o webhook atrasa;
- uma fatura tem desconto, crédito e consumo excedente ao mesmo tempo;
- o provedor fica indisponível;
- o financeiro precisa explicar de onde veio um valor.
Cada exceção cria estado. E cada estado precisa ter uma fonte de verdade.
Quando preço, pagamento e acesso compartilham a mesma coluna, corrigir uma exceção pode criar outra. Uma retentativa de webhook libera acesso duas vezes. Um ajuste manual de saldo não aparece na conciliação. Uma troca de plano apaga o contexto usado para calcular a próxima fatura.
O saldo precisa ter história
Um número sozinho responde quanto existe agora. Não responde por quê.
Crédito, consumo e estorno funcionam melhor como movimentos imutáveis num ledger. O saldo passa a ser o resultado desses movimentos. Assim, uma divergência deixa de ser um mistério e vira uma sequência que pode ser inspecionada.
O mesmo vale para a fatura. Ela não deveria depender do estado atual do plano para explicar uma cobrança antiga. Preço publicado precisa ser tratado como versão: o contrato usado naquela cobrança continua existindo mesmo depois de uma mudança comercial.
Pagamento confirmado não é acesso liberado
Pagamento e acesso se relacionam, mas não são o mesmo evento.
O provedor confirma que uma cobrança foi paga. O produto decide qual direito nasce dessa confirmação: renovar uma assinatura, adicionar créditos, liberar um arquivo ou iniciar um período de uso.
Separar essas etapas permite repetir uma sem duplicar a outra. Essa é a diferença entre “recebemos um webhook” e “processamos esse evento exatamente uma vez”.
A fronteira útil
Você não precisa começar com uma plataforma de billing. Precisa saber onde a feature termina.
Uma fronteira saudável aparece quando:
- eventos de uso têm identidade própria;
- preços publicados são versionados;
- faturas guardam os itens que explicam o total;
- pagamentos têm estado separado do acesso;
- efeitos de webhook são idempotentes;
- ajustes financeiros viram movimentos, não edições silenciosas.
Esse desenho pode continuar dentro do produto. Mas já não é só uma tela de checkout. É infraestrutura de receita.
A documentação da Infi mostra uma implementação dessa separação: catálogo, medição, fatura, pagamento e entrega como partes conectadas, mas independentes.