Vibe Coding

Como Integrar Pagamentos no App Feito com IA: Stripe, Pix e Supabase [2026]

Time da MarfinTime da Marfin18 min de leitura
Como Integrar Pagamentos no App Feito com IA: Stripe, Pix e Supabase [2026]

TL;DR

  • Stripe com Supabase é a combinação que usamos para cobrar em apps feitos com IA, porque resolve cartão, Pix e assinatura com o backend que o app já tem.

Levar para a IA

Leve este artigo para o ChatGPT, o Claude ou a sua IA preferida.

Um app feito com IA que ainda cobra por Pix manual no WhatsApp está deixando dinheiro na mesa. Integrar pagamentos no app é o passo que transforma um projeto de fim de semana em negócio, e em 2026 isso leva uma tarde, com o Stripe fazendo a cobrança e o Supabase guardando quem pagou o quê. Na Marfin já colocamos cobrança em apps que nasceram no Lovable, no Cursor e no Claude Code, e o caminho é sempre o mesmo, com as mesmas armadilhas.

O problema é que a maioria dos tutoriais para no botão de checkout. O botão é a parte fácil. O que separa um app que cobra de verdade de um app que quase cobra está no que acontece depois do clique: o webhook que confirma o pagamento, a tabela que registra a assinatura, a regra de segurança que libera o conteúdo pago e o cancelamento que funciona sem ninguém mexer no banco na mão.

Este guia cobre tudo isso na ordem em que fazemos: escolha do meio de pagamento no Brasil, preparação da conta e do banco, os cinco passos da integração Stripe com Supabase, Pix e boleto, nota fiscal, os prompts que usamos para a IA gerar o código e uma tabela com o que cada peça custa hoje.

Stripe, Mercado Pago ou plataforma brasileira: onde cobrar

Antes de escrever uma linha, a decisão que mais pesa é qual processador vai receber o dinheiro. Para apps de assinatura feitos com IA, nós usamos Stripe na maioria dos casos, e o motivo é prático: a API é a mais bem documentada do mercado, todos os modelos de IA conhecem ela de cor, e o Stripe no Brasil já aceita cartão, Pix e boleto na mesma conta. Um app que precisa explicar seu modelo de cobrança para o Claude Code em duas frases e receber uma integração funcionando ganha muito com isso.

O Stripe exige CNPJ para abrir conta no Brasil, o que elimina o cenário de pessoa física testando uma ideia. Se o app ainda está na fase de descobrir se alguém paga, o Mercado Pago aceita CPF e resolve o teste inicial com o Checkout Pro, embora a API seja mais trabalhosa e menos conhecida pelos modelos de IA. Pagar.me e Asaas são fortes quando o volume cresce e vale negociar taxa, ou quando boleto e cobrança recorrente por Pix são o coração do produto. A Abacate Pay entrou nesse mercado com Pix a taxa fixa de centavos por transação e uma API simples que os vibe coders adotaram rápido.

Plataformas como Hotmart e Kiwify resolvem cobrança, nota fiscal e afiliados de uma vez, mas cobram perto de 10% e foram desenhadas para curso e infoproduto, o que trava quando o produto é software com login e uso contínuo. Para quem está construindo um SaaS de verdade, com plano mensal e área logada, a combinação Stripe com Supabase continua sendo o padrão que recomendamos.

O que muda com Pix no Stripe

O Pix chegou ao Stripe no Brasil e mudou a conta. Cartão custa 3,99% mais R$ 0,39 por transação doméstica, enquanto Pix custa 1,19%. Numa assinatura de R$ 49 por mês, a diferença é R$ 2,35 contra R$ 0,58, o que parece pouco até multiplicar por mil assinantes durante um ano. Para pagamento único, como um plano anual ou um pacote de créditos, oferecer Pix como primeira opção aumenta a conversão porque muita gente no Brasil simplesmente evita colocar cartão em app novo.

A limitação é que o Pix do Stripe funciona só para pagamento único. Assinatura mensal no cartão renova sozinha, enquanto assinatura por Pix precisa de uma nova cobrança a cada ciclo, com o cliente pagando ativamente. Nós resolvemos isso com plano anual por Pix e plano mensal por cartão, e a maioria dos apps que atendemos converge para esse desenho depois de um ou dois meses olhando os números.

O que precisamos antes de integrar pagamentos no app

Uma conta Stripe verificada com CNPJ, um projeto no Supabase com autenticação funcionando e um modelo de cobrança definido no papel. Parece óbvio, mas já vimos gente pedir para o Claude Code "adicionar Stripe" sem saber se ia cobrar assinatura, pagamento único ou crédito por uso, e o resultado foi uma integração que fazia as três coisas pela metade.

O modelo de cobrança define a estrutura do banco. Assinatura precisa de uma tabela que guarde o status atual, o plano, a data de renovação e o identificador do cliente no Stripe. Pagamento único precisa de uma tabela de pedidos com o que foi comprado e se foi pago. Crédito por uso precisa de saldo e de um histórico de consumo. Cada um desses desenhos é simples isolado, e vira bagunça quando alguém tenta fazer os três com uma tabela só.

A autenticação do Supabase precisa estar pronta antes, porque o pagamento sempre está preso a um usuário. O fluxo completo é: o usuário cria conta no app, clica em assinar, a gente cria uma sessão de checkout no Stripe já com o ID desse usuário nos metadados, o Stripe cobra, avisa a gente por webhook, e a gente marca no banco que aquele usuário está pago. Sem login, falta a quem dar acesso. Se o app foi feito no Lovable, o tutorial de Lovable que publicamos mostra como ligar a autenticação do Supabase antes de chegar nessa etapa.

A chave secreta nunca vai pro frontend

O Stripe entrega duas chaves: a publicável, que começa com pk_, e a secreta, que começa com sk_. A publicável pode aparecer no código do navegador. A secreta cria cobranças, faz reembolsos e lê dados de todos os clientes, e por isso vive só no servidor. No nosso caso, servidor significa Edge Function do Supabase, com a chave guardada como segredo do projeto e nunca em arquivo .env commitado.

Esse é o erro que mais vemos em app feito por IA sem revisão. O modelo, tentando ser prestativo, coloca a chave secreta num arquivo do React porque foi ali que o usuário pediu o botão. Funciona no teste, e expõe a conta inteira em produção. Antes de qualquer deploy, buscamos "sk_live" e "sk_test" em todo o repositório, e a busca tem que voltar vazia.

Como integrar pagamentos no app com Stripe Checkout e Supabase, passo a passo

O desenho que usamos tem cinco peças: a tabela de assinaturas, a função que cria o checkout, a função que recebe o webhook, a política de acesso no banco e o portal do cliente. Vamos passar por cada uma na ordem em que construímos.

Passo 1: modelar a assinatura no banco

A tabela mínima liga o usuário do Supabase ao cliente do Stripe e guarda o estado da assinatura. Nós criamos ela por migration, com Row Level Security ligado desde o começo:

create table public.subscriptions (
  user_id uuid primary key references auth.users(id) on delete cascade,
  stripe_customer_id text unique,
  stripe_subscription_id text unique,
  status text not null default 'inactive',
  price_id text,
  current_period_end timestamptz,
  updated_at timestamptz default now()
);

alter table public.subscriptions enable row level security;

create policy "usuario le a propria assinatura"
  on public.subscriptions for select
  using (auth.uid() = user_id);

Repare que o usuário só tem política de leitura. Quem escreve nessa tabela é o webhook, usando a service role do Supabase, que ignora RLS. O usuário lê o próprio status e nada mais. Essa decisão elimina a categoria inteira de bug em que alguém chama a API do app e se marca como pago.

Passo 2: criar a sessão de checkout numa Edge Function

O botão de assinar no frontend chama uma Edge Function, que valida o token do usuário logado, cria a sessão no Stripe e devolve a URL do checkout hospedado. Usamos o Checkout hospedado do Stripe em vez de montar formulário de cartão, porque ele já resolve 3D Secure, Pix, boleto, cupom e recibo sem código nosso:

import Stripe from "npm:stripe@17";
import { createClient } from "npm:@supabase/supabase-js@2";

const stripe = new Stripe(Deno.env.get("STRIPE_SECRET_KEY")!);
const appUrl = Deno.env.get("APP_URL")!;

Deno.serve(async (req) => {
  const authHeader = req.headers.get("Authorization")!;
  const supabase = createClient(
    Deno.env.get("SUPABASE_URL")!,
    Deno.env.get("SUPABASE_ANON_KEY")!,
    { global: { headers: { Authorization: authHeader } } },
  );
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) return new Response("Unauthorized", { status: 401 });

  const { priceId } = await req.json();
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    customer_email: user.email,
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: appUrl + "/sucesso",
    cancel_url: appUrl + "/planos",
    metadata: { user_id: user.id },
  });
  return Response.json({ url: session.url });
});

O detalhe que faz tudo funcionar é o metadata com o user_id. Ele volta no webhook e é o que permite ligar o pagamento à conta certa. Sem isso, o webhook recebe um e-mail e precisa adivinhar quem é, e e-mail duplicado ou trocado vira bug de acesso. Os meios de pagamento aceitos vêm da configuração do painel do Stripe, então cartão, Pix e boleto aparecem no checkout sem mudar o código quando você ativa cada um.

Passo 3: receber o webhook e atualizar o Supabase

O webhook é uma segunda Edge Function, sem verificação de JWT do Supabase, porque quem chama é o Stripe e não um usuário logado. A segurança vem da assinatura que o Stripe envia no cabeçalho, verificada com o segredo do endpoint. Depois de verificar, a função lê o evento e grava o estado na tabela usando a service role:

const admin = createClient(
  Deno.env.get("SUPABASE_URL")!,
  Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
);

const event = await stripe.webhooks.constructEventAsync(
  await req.text(),
  req.headers.get("stripe-signature")!,
  Deno.env.get("STRIPE_WEBHOOK_SECRET")!,
);

if (event.type === "checkout.session.completed") {
  const session = event.data.object;
  await admin.from("subscriptions").upsert({
    user_id: session.metadata!.user_id,
    stripe_customer_id: session.customer as string,
    stripe_subscription_id: session.subscription as string,
    status: "active",
  });
}

Os eventos que tratamos em todo app são quatro: checkout concluído, assinatura atualizada, assinatura cancelada e pagamento de fatura falhado. Os dois últimos são os que os tutoriais esquecem, e são os que evitam que um cliente com cartão recusado continue usando o produto três meses de graça. Cada evento vira um upsert na tabela, e a função devolve 200 rápido, porque o Stripe reenvia qualquer evento que fique sem resposta em poucos segundos, e um webhook lento acaba processando o mesmo pagamento duas vezes.

Passo 4: liberar o acesso com RLS

Com a tabela de assinaturas atualizada, a liberação do conteúdo pago acontece no banco, com uma política que consulta o status. Se o app tem uma tabela de relatórios que só assinante vê, a política de select checa se existe assinatura ativa para o usuário atual. O frontend continua mostrando um cadeado bonito, mas quem decide é o Postgres, e isso vale mesmo se alguém abrir o console do navegador e chamar a API direto.

Para apps com muita tabela paga, criamos uma função SQL que responde se o usuário atual está ativo e reutilizamos ela em todas as políticas. Fica um lugar só para mudar a regra quando entra um plano novo ou um período de teste grátis, e a IA entende essa função com facilidade quando pedimos para estender o modelo depois.

Passo 5: portal do cliente e cancelamento

Trocar cartão, mudar de plano e cancelar são funções que o Stripe entrega prontas no Customer Portal. Uma terceira Edge Function cria a sessão do portal para o cliente logado e devolve a URL. O que o cliente fizer lá volta por webhook e atualiza a tabela. Nós nunca construímos tela de cancelamento própria, porque o portal já lida com pró-rata, reembolso e a regra de cancelar no fim do período pago.

Depois que os cinco passos estão no ar, o deploy do app com IA precisa incluir o registro do endpoint de webhook na URL de produção e a troca das chaves de teste pelas de produção. Esquecer a URL de produção é o motivo número um de "pagou e liberou nada" que recebemos de quem chega até aqui sozinho.

Como testar antes de cobrar um real de verdade

A Stripe CLI resolve o teste local com um comando que escuta os eventos e repassa para a função rodando na máquina: stripe listen apontando para o endereço da Edge Function servida por supabase functions serve. Com isso, um checkout feito em modo de teste dispara o webhook local e a tabela do Supabase local muda na hora. Sem essa etapa, o teste vira publicar em produção e torcer.

Os cartões de teste do Stripe cobrem os cenários que interessam: um número que aprova, um que recusa, um que exige autenticação 3D Secure e um que é salvo no cadastro do cliente e falha na hora da cobrança, o cenário da renovação recusada. Testamos os quatro em todo app, e o de renovação falhada é o que mais pega integração mal feita, porque o app precisa reagir a um evento que só chega um mês depois. O Stripe permite avançar o relógio de teste para simular esse mês em segundos, e esse recurso vale mais que qualquer teste unitário nessa parte do sistema.

Nota fiscal e imposto ficam fora do Stripe

O Stripe cobra, repassa e emite recibo. A nota fiscal de serviço, que todo SaaS no Brasil precisa emitir a cada cobrança, fica por conta de um serviço separado. Nós ligamos NFe.io ou eNotas no mesmo webhook que marca a assinatura como paga: o evento de fatura paga dispara a emissão da NFS-e com o CPF ou CNPJ que o cliente informou no cadastro, e o PDF vai por e-mail. O Asaas tem emissão nativa, o que pesa a favor dele para quem quer menos peças no sistema.

Coletar CPF ou CNPJ no cadastro, e o endereço quando a prefeitura exige, é uma decisão de produto que vale tomar antes de integrar pagamentos no app. Pedir depois, para quem já paga, custa suporte e cancelamento. Nossa regra é pedir o documento na tela de planos, antes do checkout, e guardar na mesma tabela de perfil que o app já tem.

Fazendo tudo isso com IA: os prompts que usamos

Claude Code é a ferramenta que mais usamos na Marfin para esse tipo de integração, e o Cursor é onde fazemos o building do app no dia a dia. A diferença entre pedir "adiciona Stripe" e receber algo pronto está no contexto que damos. O prompt que usamos parte do modelo de cobrança já definido e lista as cinco peças: tabela com RLS, função de checkout, função de webhook com verificação de assinatura, política de acesso e portal. Com o Opus 4.8, o Claude Code cria as migrations, as três funções e a página de planos numa rodada, e a revisão fica concentrada em conferir os quatro eventos de webhook e a ausência de chave secreta no frontend.

No Lovable, o caminho é mais curto porque a plataforma tem integração nativa com Stripe conectada ao Supabase. O Agent Mode gera as Edge Functions e pede as chaves na configuração do projeto, sem colar segredo em código. A modelagem do banco do jeito que descrevemos fica por nossa conta, então vale conversar sobre a tabela de assinaturas antes de pedir o checkout. O Bolt.new também oferece integração com Stripe e é uma opção válida, mas a experiência com Supabase é menos integrada e acabamos ajustando mais coisa na mão.

Para quem está começando pelo vibe coding e ainda está montando o app, a ordem que funciona é: fazer o app funcionar com login, colocar a cobrança com um plano só, e depois adicionar plano de equipe, cupom e período de teste. Quem tenta fazer tudo de uma vez pede à IA um sistema de billing completo e recebe um sistema de billing pela metade. Se a dúvida é qual ferramenta escolher para esse trabalho, a comparação das melhores IDEs com IA em 2026 cobre Claude Code, Cursor e Windsurf lado a lado.

Um atalho que vale conhecer: o Supabase mantém um wrapper de dados que permite consultar clientes e assinaturas do Stripe direto por SQL, sem sincronizar tabela. Serve para relatório e conciliação sem código extra, enquanto a liberação de acesso continua no webhook, porque a consulta remota é lenta demais para rodar em cada requisição.

Stripe vs Mercado Pago vs Pagar.me vs Asaas para apps feitos com IA

O Stripe ganha em documentação, em conhecimento dos modelos de IA e em completude para assinatura. Perde na exigência de CNPJ e na ausência de Pix recorrente automático. É a escolha padrão para SaaS com área logada.

O Mercado Pago ganha na abertura de conta com CPF, na confiança que o brasileiro médio tem na marca dentro do checkout e no Pix a 0,99%. Perde numa API mais confusa, com mais versões e menos exemplos, o que se traduz em mais rodadas de correção quando a IA gera o código. É a escolha para validar ideia antes de abrir empresa.

Pagar.me e Asaas ganham em taxa negociada quando o volume passa de algumas dezenas de milhares por mês e em recursos de cobrança brasileira, como boleto com juros e multa, Pix recorrente com aviso automático e emissão de nota fiscal integrada no caso do Asaas. Perdem na curva de integração e na dependência de contrato comercial. São a escolha para app que cobra pequeno negócio brasileiro por boleto e Pix.

A Abacate Pay ganha em simplicidade e na taxa fixa por Pix, que fica imbatível em ticket alto. Perde em maturidade e em recursos de assinatura. É a escolha para pagamento único por Pix, como venda de crédito ou plano anual.

Para quem ainda decide se o produto vai ser um app pago ou uma ferramenta grátis com upsell, o guia de como criar app sem programar mostra o caminho até o ponto em que a cobrança entra.

Preços e planos

ItemCusto em 2026
Stripe, cartão nacional3,99% + R$ 0,39 por transação
Stripe, cartão internacionalacréscimo de 2%, mais 2% se houver conversão de moeda
Stripe, Pix1,19% por transação
Stripe, boletoR$ 3,45 por boleto pago
Stripe Billing (assinaturas)0,7% sobre o volume recorrente no plano Starter
Supabase FreeUS$ 0, 500 MB de banco, 500 mil invocações de Edge Function por mês
Supabase ProUS$ 25 por mês, 8 GB de banco, 2 milhões de invocações, projeto sem pausa
Supabase TeamUS$ 599 por mês, SSO, mais retenção de logs e suporte
Mercado Pago, Pix0,99% por transação
Mercado Pago, cartão3,98% a 4,98% conforme o prazo de repasse

Na prática, um app com 100 assinantes a R$ 49 no cartão paga ao Stripe algo perto de R$ 270 por mês entre taxa de transação e Billing, ou cerca de 5,5% do faturamento. O mesmo app recebendo tudo por Pix anual pagaria menos de R$ 70. O Supabase Free segura o começo, mas tem uma pegadinha: projeto grátis sem atividade por uma semana entra em pausa, e um webhook batendo num projeto pausado perde o pagamento. Por isso a primeira cobrança real acontece já no plano Pro, e os US$ 25 por mês viram a assinatura mais barata da operação.

8 dicas para integrar pagamentos no app sem dor de cabeça

1. Comece com um plano só. Um preço, um checkout, um webhook. Plano de equipe, cupom e teste grátis entram depois, quando o fluxo básico já roda em produção por algumas semanas e você sabe o que os clientes pedem.

2. Guarde o ID do usuário nos metadados do checkout. É a única forma confiável de ligar um pagamento a uma conta. E-mail muda, e-mail repete, e o Stripe cria cliente novo com facilidade. O user_id do Supabase resolve tudo isso.

3. Trate os quatro eventos de webhook desde o primeiro dia. Checkout concluído, assinatura atualizada, assinatura cancelada e fatura falhada. Quem só trata o primeiro descobre meses depois que tem cliente inadimplente usando o produto.

4. Use o Customer Portal em vez de tela própria. O portal cuida de troca de cartão, mudança de plano, cancelamento e pró-rata, com as regras que você define no painel. Construir isso na mão custa semanas e ainda sai com bug.

5. Peça à IA para procurar chave secreta no repositório. Antes de cada deploy, o Claude Code roda uma busca por sk_live e sk_test e confirma que a única ocorrência está nos segredos do Supabase. Um minuto de revisão evita uma conta comprometida.

6. Ofereça Pix no plano anual e cartão no mensal. O Pix converte melhor e custa menos, mas exige pagamento ativo a cada ciclo. Casar o meio de pagamento com o ciclo de cobrança resolve os dois lados.

7. Suba para o Supabase Pro antes da primeira cobrança real. Projeto grátis pausa depois de uma semana sem uso e engole webhook. Os US$ 25 por mês são a proteção mais barata que existe contra pagamento sem acesso liberado.

8. Registre o webhook de produção como item do checklist de deploy. Chaves de produção, endpoint de webhook na URL final e segredo do endpoint atualizado na Edge Function. Os três juntos, sempre, porque qualquer um faltando quebra o fluxo de forma silenciosa.

Cobrar pelo app é onde o vibe coding encontra a realidade de operar um produto. A IA escreve a integração em uma tarde, e o que fica com a gente é decidir o modelo de cobrança, revisar a segurança e testar o caminho que o dinheiro faz até a tabela de assinaturas. Feito com esse cuidado, o mesmo desenho aguenta do primeiro cliente até os primeiros milhares sem reescrita, e cada plano novo vira uma migration e uma linha a mais no webhook.


Leia também:

▸ THE_DOWNLOAD.SUBSCRIBE

Carregue a semana.
Instale na segunda.

Um digest do blog da Marfin. Todo sábado.

Grátis. Eject quando quiser.

A Marfin é uma venture builder de empresas tech.

Quer conhecer nossos serviços e produtos?