Todos os artigos
StripeStripe Connectmarketplacewebhook debugging

Webhooks do Stripe Connect: o guia de testes locais

O Stripe Connect é um ecossistema de webhooks diferente do Stripe normal. A matemática da assinatura é a mesma. Todo o resto é diferente. Se você andou caçando por que seu handler do Connect ignora em silêncio account.application.deauthorized, este artigo é para você.

O Connect muda quais eventos você recebe

Webhooks do Stripe normal vêm da sua conta de plataforma: charges, customers, subscriptions. Webhooks do Connect vêm de contas conectadas e de eventos de ciclo de vida específicos do Connect na sua plataforma. A lista se sobrepõe bastante mas inclui eventos que você só vê com o Connect habilitado:

  • account.updated — status de verificação, capabilities, requisitos
  • account.application.deauthorized — a conta conectada revogou seu acesso
  • capability.updated — estados de ativação de payouts/transfers
  • person.created, person.updated — para contas Custom e Express
  • payout.failed, payout.paid — na conta conectada, não na sua plataforma

A maioria dos times descobre isso depois de fazer deploy. Testes locais trazem o problema à tona em minutos.

O cabeçalho Stripe-Account muda tudo

Quando um evento acontece numa conta conectada, o Stripe anexa um cabeçalho Stripe-Account com o ID da conta conectada (acct_xxx). Seu handler precisa rotear por esse cabeçalho, não pelo que estiver dentro do payload.

const connectedAccountId = req.headers['stripe-account'];
const event = stripe.webhooks.constructEvent(
  rawBody,
  req.headers['stripe-signature'],
  endpointSecret,
);

// Now process the event in the context of connectedAccountId
await handleConnectEvent(event, connectedAccountId);

Se você esquecer de ler o cabeçalho, seu handler trata cada evento do Connect como se tivesse acontecido na sua plataforma. Bugs desse padrão geralmente aparecem como "o payout aparece para o comerciante errado".

Testar o Connect localmente com o PortPreview

A configuração é a mesma do teste local de Stripe normal, mais um passo extra:

  1. Rode seu app de plataforma localmente.
  2. Inicie um túnel: npx portpreview 3000.
  3. No dashboard do Stripe, adicione a URL do túnel como endpoint de webhook e marque a opção Events on Connected accounts. Esse é o toggle que muda o stream de eventos inteiro.
  4. Use uma conta conectada de teste Express ou Custom. O modo de teste do Stripe inclui um criador de conta falso "Jenny Rosen" que dispara eventos realistas.
  5. Dispare eventos da interface de teste do Connect: complete o onboarding, solicite um payout, desautorize uma conta.

O fluxo de desautorização é o difícil

Quando uma conta conectada revoga o acesso da sua aplicação, o Stripe dispara account.application.deauthorized exatamente uma vez. Se seu handler quebra, retorna um 5xx ou não confirma o evento a tempo, o Stripe tenta de novo — mas a conta conectada já se foi. Suas chamadas de API subsequentes para essa conta retornam 401.

Teste o fluxo de deauth com cuidado. Use o modo de teste do Connect para desautorizar a conta de teste, capture o webhook, e rode sua lógica de limpeza contra o payload capturado. Faça replay até o caminho ficar à prova de balas.

Express vs Standard vs Custom

O tipo de conta muda quais eventos de person/capability você recebe. Contas Express e Custom emitem eventos person.* porque sua plataforma ajuda a completar o onboarding. Contas Standard tratam o próprio onboarding por telas hospedadas pelo Stripe, então você vê menos eventos. Se você troca de tipo de conta no meio do projeto — e as pessoas trocam — seu handler de webhooks precisa de ajuste.

O que de fato faríamos

Para um marketplace real com analytics em nível de plataforma e relatórios por comerciante, construa dois caminhos de handler distintos desde o dia um: um para eventos de plataforma (sem cabeçalho Stripe-Account), outro para eventos de contas conectadas. Roteie no topo da função. Isso evita 90% dos bugs de "isso é para nós ou para o comerciante" depois.

Webhooks do Connect compartilham o esquema de assinatura do Stripe, então a mecânica de verificação é idêntica ao teste de webhooks de Stripe normal. Para contexto sobre a matemática de assinatura entre provedores, veja o guia de verificação de assinatura. Entre na lista de espera do PortPreview para testar o Connect com captura e replay embutidos.

Perguntas frequentes

Como os webhooks do Stripe Connect diferem dos webhooks do Stripe normal?
Os eventos do Connect vêm de contas conectadas e carregam um cabeçalho Stripe-Account que identifica qual conta disparou o evento. O mecanismo de assinatura é o mesmo do Stripe normal, mas você precisa habilitar Events on Connected accounts no dashboard e rotear pelo cabeçalho no seu handler.
Para que serve o cabeçalho Stripe-Account?
Ele identifica a conta conectada que disparou o evento. Seu handler deve lê-lo antes de processar porque o mesmo tipo de evento pode disparar na sua plataforma ou numa conta conectada, e a lógica de negócio difere.
Como testo o webhook de desautorização localmente?
Configure um endpoint do Connect com um túnel, conecte uma conta de teste Express ou Custom, depois desautorize-a pela interface de teste do Connect. O evento account.application.deauthorized chega ao seu handler local — faça replay conforme necessário enquanto ajusta a lógica de limpeza.