Stripe em um app construído com IA: cinco bugs de pagamento para corrigir
Apps feitos com IA costumam marcar pedidos como pagos pelo navegador. Cinco bugs de Stripe que custam dinheiro, como achá-los e o que a documentação recomenda.
Nesta página · 6 seções
Principais pontos
- O bug de pagamento mais comum em apps construídos com IA é liberar o acesso quando o navegador chega à página de sucesso. A própria documentação do Stripe diz que não dá para confiar nessa página.
- Processe os pedidos a partir de um webhook verificado, garanta que o processamento possa rodar duas vezes sem problema e pegue os preços do seu servidor, nunca do navegador.
- Cada bug abaixo pode ser identificado em poucos minutos lendo uma função ou fazendo uma compra de teste.
Adicionar o Stripe a um app construído com IA parece fácil: a ferramenta de IA gera um botão de checkout, você faz um pagamento de teste e aparece uma página de sucesso. O problema é o que acontece por trás dessa página. Em muitos protótipos, o app decide que o cliente pagou porque o navegador disse isso, e qualquer pessoa que consiga editar uma requisição no navegador também pode dizer isso.
Estes são os cinco bugs de pagamento que vale corrigir antes de receber dinheiro de verdade, cada um com o que a documentação do Stripe recomenda. Este post faz parte do guia para deixar um protótipo construído com IA pronto para usuários reais.
1. O acesso é liberado na página de sucesso
O app mostra uma página de “Obrigado pela sua compra” depois do checkout e, nessa página, marca o pedido como pago ou ativa a assinatura. Duas coisas dão errado: clientes que pagam e fecham a aba nunca recebem o que pagaram, e qualquer pessoa que descubra a URL de sucesso pode acessá-la sem pagar.
O Stripe é direto sobre isso: “Você não pode depender de disparar o processamento do pedido apenas a partir da página de destino do checkout, porque não há garantia de que os clientes visitem essa página” (Stripe). A correção é um webhook: o Stripe chama o seu servidor com um evento checkout.session.completed, e o seu servidor libera o acesso. A página de sucesso pode então mostrar o resultado, mas deixa de ser ela quem decide.
Como identificar: procure no código o ponto em que um pedido ou assinatura passa a ser “pago” ou “ativo”. Se isso acontece em um componente de página ou depois de um redirecionamento, é este bug.
2. O webhook não verifica a assinatura
Depois que o webhook existe, qualquer pessoa pode enviar requisições para a URL dele. O Stripe assina cada evento com um segredo que só você e o Stripe conhecem, e alerta que, “sem verificação, um atacante poderia enviar eventos de webhook falsos para o seu endpoint para disparar ações como processar pedidos, liberar acesso a contas ou modificar registros” (Stripe).
A verificação é uma única chamada de função nas bibliotecas do Stripe, usando o corpo bruto da requisição, o header Stripe-Signature e o seu signing secret whsec_…. Uma falha comum em código gerado por IA é converter o corpo para JSON antes, o que o altera e faz a verificação falhar; a “correção” acaba sendo remover a verificação.
Como identificar: abra o handler do webhook. Se ele lê event.type sem chamar antes uma função de verificação, qualquer pessoa pode forjar um pagamento.
3. O mesmo pagamento é processado duas vezes
O Stripe reenvia eventos que não recebem uma resposta de sucesso rápida, por até três dias no modo live, e diz que os endpoints “podem ocasionalmente receber o mesmo evento mais de uma vez” (Stripe). Se o seu handler adiciona créditos, envia uma chave de licença ou cria um pedido toda vez que roda, alguns clientes vão receber isso duas vezes.
A orientação do Stripe é registrar os IDs dos eventos já processados e ignorar os repetidos, e tornar o processamento “seguro para rodar várias vezes, inclusive de forma concorrente” (Stripe). Na prática: guarde o ID da Checkout Session junto com o pedido e use uma restrição de unicidade para que uma segunda inserção falhe.
Como identificar: reenvie um evento pelo painel do Stripe. Se o cliente receber algo em dobro, é este bug.
4. O preço vem do navegador
O botão de checkout envia o valor para o seu servidor, ou direto para o Stripe a partir do frontend. Qualquer pessoa pode trocar 4900 por 100 na requisição e comprar por um dólar.
A correção é criar os preços no Stripe (ou mantê-los no seu servidor) e fazer o navegador enviar apenas qual produto e a quantidade. O seu servidor consulta o preço e cria a Checkout Session. O mesmo vale para descontos, nomes de planos e quantidades: o navegador pede, o servidor decide.
Como identificar: olhe a requisição que o botão de checkout envia. Se ela contém um valor ou um preço, é este bug.
5. Só o primeiro pagamento é tratado
Protótipos normalmente tratam um único evento: o primeiro checkout bem-sucedido. Pagamentos reais têm uma vida depois disso. Transferências bancárias e outros métodos com confirmação posterior são concluídos mais tarde, e o Stripe envia checkout.session.async_payment_succeeded ou …_failed quando isso acontece (Stripe). Assinaturas são renovadas, falham, são canceladas e são contestadas, cada uma com seu próprio evento.
Se o app só escuta o primeiro evento, clientes cujo cartão falha no mês seguinte mantêm o acesso para sempre, e clientes que pagaram por transferência bancária nunca o recebem. Liste os eventos dos quais o seu negócio depende e trate cada um deles, sem presumir que chegam em ordem: o Stripe não garante a ordem dos eventos.
Como identificar: no painel do Stripe, veja em quais tipos de evento o seu endpoint de webhook está inscrito. Se for apenas checkout.session.completed e você vende assinaturas, é este bug.
O que verificar antes de entrar em produção?
- Use chaves de teste e de produção separadas, guardadas apenas no servidor. A chave secreta (
sk_live_…) nunca vai para o frontend; veja chaves secretas no seu frontend. - Registre o endpoint de webhook de produção separadamente: os endpoints de teste e de produção têm signing secrets diferentes.
- Faça uma compra real com um cartão real, faça o reembolso e confira se o acesso foi liberado e depois tratado corretamente.
Perguntas frequentes
Preciso de webhooks do Stripe se uso o Stripe Checkout?
Sim. O Stripe diz que você não pode depender só da página de sucesso para processar pedidos, porque os clientes podem nunca chegar a ela. Webhooks são obrigatórios se você vende assinaturas ou aceita métodos de pagamento com confirmação posterior, como transferências bancárias.
Como impedir requisições falsas de webhook do Stripe?
Verifique a assinatura de cada evento com a biblioteca do Stripe, usando o corpo bruto da requisição, o header Stripe-Signature e o signing secret do seu endpoint. Rejeite qualquer evento que falhe na verificação antes de fazer qualquer coisa com ele.
Por que meu cliente foi cobrado uma vez, mas recebeu dois pedidos?
O Stripe pode entregar o mesmo evento mais de uma vez e reenvia eventos que dão timeout. Registre o ID de cada Checkout Session ou evento ao processá-lo e ignore qualquer ID que você já tenha processado.