O que uma auditoria do nosso próprio sistema de pagamento revelou
Duas descobertas críticas, e nenhuma estava onde teríamos procurado. Um relato aberto sobre erros que já foram corrigidos.

Em agosto de 2026 revisamos nosso sistema de pagamento do zero. Não porque algo tivesse acontecido, mas porque ele tinha entrado no ar pouco antes e queríamos saber o que tínhamos deixado passar.
Tínhamos deixado passar bastante coisa. Este artigo nomeia as descobertas. Tudo o que está descrito aqui foi corrigido, e a maior parte já estava no changelog público de qualquer forma.
O erro de modelagem de onde vieram as duas descobertas críticas
Quando alguém compra Premium conosco, um cadastro de cliente é criado no nosso provedor de pagamento. Armazenamos esse cadastro pelo ID do servidor, afinal o Premium vai para um servidor.
Esse é exatamente o modelo errado, e foi a raiz das duas descobertas mais graves.
Um cadastro de cliente pertence a um comprador. Ele carrega o método de pagamento, o histórico de faturas e, assim que alguém paga por dois servidores, várias assinaturas. Indexá-lo pelo ID do servidor significa que várias pessoas apontam para a mesma linha.
Descoberta 1: dados de cliente de outra pessoa, sobrescrevíveis sem pagar
A compra está aberta a qualquer membro de um servidor, e a função que busca ou cria o cadastro de cliente roda antes do pagamento. Ela encontrava a linha pelo ID do servidor e a reescrevia em silêncio para o novo interessado, incluindo o endereço de e-mail dele no provedor de pagamento.
Na prática, isso significava: bastava um clique num servidor em que alguém tinha comprado em algum momento. Depois disso, as faturas de todas as assinaturas daquele comprador original teriam ido para o endereço de e-mail do estranho. Sem pagamento, sem confirmação.
Corrigido verificando, antes de qualquer reaproveitamento, se o cadastro realmente pertence a esta conta. Se não pertencer, um cadastro separado é criado e o outro fica intocado.
Descoberta 2: o portal de cobrança expunha assinaturas de outras pessoas
O mesmo erro de modelagem, um nível adiante. A verificação de propriedade valia para a assinatura do servidor, mas a sessão do portal era aberta para o cadastro de cliente, que por design pode carregar vários servidores.
Assim, qualquer pessoa que comprasse legitimamente em um servidor podia ver e gerenciar as assinaturas que o mesmo cadastro carregava para outros servidores.
Corrigido resolvendo o cadastro de cliente a partir da compra específica, e não da linha do servidor.
Duas descobertas em que o código contradizia nossos próprios termos
Esta é a categoria que mais nos incomodou, porque não é técnica.
A lista negra tirava tempo já pago. Nossos termos dizem que uma assinatura termina no fim do período atual. Mas, ao bloquear um servidor, o código pedia o cancelamento imediato: sem reembolso e, a partir daquele momento, sem serviço por um período já pago. O código fazia algo diferente do que tínhamos prometido por escrito. Agora o período pago vai até o fim.
A renúncia ao direito de arrependimento não era comprovável. Antes de uma compra, você precisa confirmar que o serviço começa imediatamente. Essa confirmação existia só no navegador, nunca era enviada e nunca era armazenada em lugar nenhum. O ônus da prova é nosso, e simplesmente não tínhamos prova. Agora o consentimento é um campo obrigatório da rota de checkout, armazenado com data e hora e com um texto versionado, e o próprio texto é versionado: um texto existente nunca é editado, sempre se cria uma nova versão, senão os registros antigos não seriam mais reproduzíveis.
A segunda rodada foi pior que a primeira
Depois das primeiras 21 descobertas, olhamos de novo algumas semanas depois. Foi a decisão certa, porque a descoberta mais grave de todas só apareceu ali.
Um reembolso no servidor B apagava a licença vitalícia paga do servidor A. Notificações de reembolso e de chargeback citam só um pagamento, não um servidor. Nós as resolvíamos pelo cadastro de cliente. Como na primeira rodada tínhamos estabelecido corretamente que um cadastro pertence a um comprador em vários servidores, essa mesma resolução deixou de ser inequívoca. Alguém que tinha pago por dois servidores e recebido um reembolso por um deles podia perder a licença vitalícia do outro.
A resolução agora passa por quatro etapas exatas, e tudo o que não puder ser resolvido de forma inequívoca é reportado em vez de adivinhado.
Um chargeback ganho não restaurava nada. Num chargeback, o código apagava a linha da compra, a única prova de que aquele servidor algum dia teve uma licença vitalícia. Ganhar a disputa depois não podia desfazer isso. Agora ele marca em vez de apagar.
A retenção de dados apagava servidores pagos. Quando o bot sai de um servidor, os dados dele são removidos após 30 dias. Essa limpeza nunca perguntava se havia uma assinatura ativa vinculada.
O que levamos disso
Os bugs não estavam no código de pagamento. Nenhuma descoberta crítica dizia respeito a um valor, uma moeda ou um cálculo. Todas estavam no modelo por trás: quem é dono de um cadastro de cliente, quem é dono de um pagamento, quem é dono de um servidor. Quem audita um sistema de pagamento olhando para os valores está olhando para longe da parte perigosa.
Uma auditoria precisa de uma segunda rodada. A descoberta mais grave foi consequência direta de uma correção da primeira. Não é coincidência: corrigir um modelo invalida suposições que ainda valem em outros lugares.
"Nossos termos dizem isso" é uma frase verificável. Duas descobertas eram divergências entre o que tínhamos prometido por escrito e o que o código fazia. Isso pode ser lido, e ninguém lê, porque parece direito e não engenharia.
As condições de compra completas estão nos nossos termos de serviço, e o direito de arrependimento em arrependimento.
Mais artigos
A lei dentro do nosso código
Um botão de cancelamento que precisa funcionar sem login. Um formulário que nunca pode rejeitar você. Por que deveres legais são arquitetura para nós, e não texto padrão.
BastidoresPor que quase tudo no AlphaCloud continua grátis
A maioria dos bots do Discord tranca seus recursos mais úteis atrás de uma assinatura. Nós deliberadamente não fazemos isso, e isso tem menos a ver com generosidade do que parece.
BastidoresDe olho em 4.000 servidores do Discord: Grafana, PostHog e o que eles nos mostraram
Um loop que causava em silêncio metade do nosso tráfego, três milhões de requisições inúteis por dia e um ataque que acabou depois de um minuto. O que o nosso monitoramento vê e o que ele deliberadamente não vê.