icardb
Stripe no Brasil: integração técnica, webhooks, Pix e o que considerar antes de escolher
Voltar para artigosNEGÓCIOS DIGITAIS

Stripe no Brasil: integração técnica, webhooks, Pix e o que considerar antes de escolher

Por Equipe Editorial Icardb 7 min de leitura

Integrar pagamentos é uma das partes mais sensíveis de qualquer produto: erros silenciosos viram cobrança duplicada, acesso liberado sem pagamento ou cliente pagante sem acesso. Este guia mostra a arquitetura recomendada de integração com Stripe, o tratamento correto de webhooks e os pontos específicos do mercado brasileiro que influenciam a escolha do provedor.

Regra número um: o servidor decide, o navegador não

Nunca libere acesso com base em um retorno de sucesso no navegador. O usuário pode fechar a página antes do redirecionamento, o pagamento pode ser aprovado depois de uma análise antifraude ou a URL de sucesso pode ser acessada diretamente. A confirmação válida chega por webhook, verificado no servidor.

EtapaOnde aconteceResponsabilidade
Escolha do planoNavegadorInterface apenas
Criação da sessão de pagamentoServidorDefinir preço e cliente; nunca aceitar valor do cliente
Coleta do cartãoAmbiente do provedorReduz escopo de conformidade PCI
Confirmação do pagamentoWebhook no servidorÚnica fonte de verdade
Liberação de acessoServidorApós evento verificado e registrado

Criando a sessão de checkout

O caminho mais rápido e seguro é usar a página de checkout hospedada pelo provedor: ela cuida de validação de cartão, autenticação adicional e localização. O servidor define o que será cobrado e a quem.

ts
import Stripe from "stripe";
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";

export const criarCheckout = createServerFn({ method: "POST" })
  .inputValidator((d) => z.object({ planoId: z.enum(["basico", "pro"]) }).parse(d))
  .handler(async ({ data }) => {
    const stripe = new Stripe(process.env["STRIPE_SECRET_KEY"]!);

    // O preço vem do servidor, jamais do cliente
    const precos = { basico: process.env["PRICE_BASICO"]!, pro: process.env["PRICE_PRO"]! };

    const sessao = await stripe.checkout.sessions.create({
      mode: "subscription",
      line_items: [{ price: precos[data.planoId], quantity: 1 }],
      success_url: "https://app.exemplo.com/assinatura/ok?session_id={CHECKOUT_SESSION_ID}",
      cancel_url: "https://app.exemplo.com/planos",
      client_reference_id: usuarioAtual.id, // vincula o pagamento ao usuário
      metadata: { tenant_id: usuarioAtual.tenantId },
    });

    return { url: sessao.url };
  });

Webhooks: assinatura verificada e processamento idempotente

O endpoint de webhook é público e precisa provar que a requisição veio mesmo do provedor. Além disso, eventos podem chegar mais de uma vez ou fora de ordem, então o processamento precisa ser idempotente: processar o mesmo evento duas vezes não pode gerar efeito duplicado.

ts
import { createFileRoute } from "@tanstack/react-router";
import Stripe from "stripe";

export const Route = createFileRoute("/api/public/stripe-webhook")({
  server: {
    handlers: {
      POST: async ({ request }) => {
        const stripe = new Stripe(process.env["STRIPE_SECRET_KEY"]!);
        const assinatura = request.headers.get("stripe-signature");
        const corpo = await request.text(); // corpo bruto: não usar JSON parseado

        let evento: Stripe.Event;
        try {
          evento = stripe.webhooks.constructEvent(
            corpo,
            assinatura!,
            process.env["STRIPE_WEBHOOK_SECRET"]!
          );
        } catch {
          return new Response("Assinatura inválida", { status: 400 });
        }

        // Idempotência: grava o id do evento antes de agir
        const novo = await registrarEventoSeInedito(evento.id);
        if (!novo) return new Response("ok"); // já processado

        switch (evento.type) {
          case "checkout.session.completed":
            await ativarAssinatura(evento.data.object);
            break;
          case "invoice.payment_failed":
            await marcarPagamentoFalho(evento.data.object);
            break;
          case "customer.subscription.deleted":
            await encerrarAcesso(evento.data.object);
            break;
        }

        return new Response("ok"); // responda rápido; trabalho pesado vai para fila
      },
    },
  },
});

Responda ao webhook em poucos segundos. Processamento longo dentro do handler causa timeout e faz o provedor reenviar o evento, aumentando a chance de duplicidade. Enfileire o trabalho demorado e confirme o recebimento imediatamente.

Eventos que importam em assinaturas

EventoSignificadoAção típica
checkout.session.completedCheckout concluídoCriar ou ativar assinatura
invoice.paidRenovação cobrada com sucessoEstender período de acesso
invoice.payment_failedFalha na cobrançaNotificar e iniciar tolerância
customer.subscription.updatedMudança de plano ou statusAjustar limites do plano
customer.subscription.deletedCancelamento efetivadoEncerrar acesso ao fim do período
charge.dispute.createdContestação abertaReunir evidências e avaliar suspensão

Particularidades do mercado brasileiro

O comportamento de pagamento no Brasil difere do padrão internacional em três pontos que afetam diretamente a conversão: uso intenso de Pix, expectativa de parcelamento no cartão de crédito e boleto em vendas para empresas. Esses fatores pesam tanto quanto a qualidade técnica da API.

CritérioProvedor internacionalGateway nacional
Documentação e APIGeralmente muito maduraVariável entre provedores
PixSuporte crescente, conferir disponibilidadeSuporte nativo consolidado
Parcelamento no créditoLimitado ou indiretoNativo, com repasse de juros
BoletoDepende do provedorPadrão de mercado
Antifraude localGenéricoAjustado ao perfil brasileiro
Suporte e cobrança em realDepende da configuraçãoLocal, em português

Confirme diretamente na documentação oficial quais métodos estão disponíveis para a sua conta e país de operação: cobertura de Pix, boleto e parcelamento muda com frequência e varia conforme o tipo de conta.

Ambiente de teste e casos que precisam ser exercitados

  1. Pagamento aprovado normalmente e liberação de acesso pelo webhook.
  2. Cartão recusado e nova tentativa bem-sucedida.
  3. Usuário fecha o navegador antes do redirecionamento — o acesso ainda deve ser liberado.
  4. Evento duplicado enviado duas vezes: verificar que o efeito ocorre uma única vez.
  5. Cancelamento no meio do ciclo e término do acesso na data correta.
  6. Falha de renovação seguida de suspensão após o período de tolerância.
bash
# Encaminhar eventos reais de teste para o ambiente local
stripe login
stripe listen --forward-to localhost:8080/api/public/stripe-webhook

# Disparar um evento específico para exercitar o handler
stripe trigger checkout.session.completed
stripe trigger invoice.payment_failed

Conformidade e obrigações

  • Nunca armazene número completo de cartão; use os elementos hospedados do provedor para manter o escopo PCI reduzido.
  • Guarde apenas identificadores do provedor, últimos dígitos e bandeira, quando necessário para suporte.
  • Emita nota fiscal conforme a legislação aplicável ao seu regime tributário; o gateway não faz isso por você.
  • Informe claramente valor, recorrência e forma de cancelamento antes da cobrança, conforme o Código de Defesa do Consumidor.
  • Trate dados de pagamento como dados pessoais sensíveis do ponto de vista de segurança e registre a base legal do tratamento.

Conclusão

Uma integração de pagamentos confiável tem sempre a mesma forma: preço definido no servidor, coleta de dados sensíveis no ambiente do provedor, confirmação exclusivamente por webhook verificado e processamento idempotente. Definida essa base, a escolha entre provedor internacional e gateway nacional passa a ser decidida pelos métodos de pagamento que seu público realmente usa e pelo custo por transação.

Aviso: Conteúdo informativo e educativo. O icardb não promete ganhos financeiros, clientes, vagas ou resultados garantidos. Resultados dependem de estudo, execução, mercado e contexto pessoal.

Perguntas frequentes

+Posso liberar o acesso na página de sucesso do checkout?

Não como fonte única de verdade. Use a página de sucesso apenas para dar retorno visual e confirme o pagamento pelo webhook, que é o único canal confiável e verificável no servidor.

+Como testar webhooks em ambiente local?

Com a CLI oficial do provedor, encaminhando eventos para a sua porta local, ou com um túnel HTTP público. Ambas as opções permitem exercitar eventos reais sem publicar a aplicação.

+O que fazer quando a renovação falha?

Configure novas tentativas automáticas, notifique o cliente com um link para atualizar o meio de pagamento e defina um período de tolerância antes de suspender. Suspensão imediata converte falha temporária em cancelamento definitivo.

+Vale usar dois provedores de pagamento?

Faz sentido quando cada um cobre um método relevante, por exemplo cartão internacional em um e Pix em outro. O custo é dobrar a lógica de conciliação e de webhooks, o que exige uma camada interna única de assinatura.

Fontes consultadas

Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.

Crédito da imagem: Foto: Equipe Editorial Icardb / Gerado por IA (Licença Editorial)

Leia também