Como lidar com webhooks do Stripe com Edge Functions
Este guia demonstra como lidar com webhooks do Stripe de forma segura usando Azion Edge Functions. Você aprenderá a processar eventos de pagamento em tempo real, verificar assinaturas de webhook e construir um sistema robusto de processamento de pagamentos na edge.
Requisitos
Antes de começar, certifique-se de ter:
- Uma conta na Azion
- Uma conta no Stripe com acesso à API
- Azion CLI instalada e configurada
- Node.js versão 18 ou superior
- Gerenciador de pacotes pnpm instalado
- Conhecimento básico de JavaScript, Edge Functions e webhooks do Stripe
- Chaves de API do Stripe (tanto chave secreta quanto secret de assinatura do webhook)
Primeiros passos
Passo 1: Configure seu ambiente de desenvolvimento
- Clone o repositório de exemplo de webhooks do Stripe:
git clone https://github.com/egermano/edge-functions-examples.gitcd edge-functions-examples/packages/stripe-webhooks
- Instale as dependências do projeto:
pnpm install
- Revise a estrutura do projeto para entender a implementação:
ls -la
Você deve ver os arquivos principais incluindo a implementação da Edge Function, manipuladores de webhook e arquivos de configuração.
Passo 2: Configure as variáveis de ambiente
- Crie um arquivo
.env
baseado no exemplo:
cp .env.example .env
- Edite o arquivo
.env
para incluir suas credenciais do Stripe:
# Configuração StripeSTRIPE_SECRET_KEY=sk_test_sua_chave_secreta_stripeSTRIPE_WEBHOOK_SECRET=whsec_seu_secret_de_assinatura_webhook
- Obtenha suas credenciais do Dashboard do Stripe:
- Chave Secreta: Disponível na seção API Keys
- Secret do Webhook: Criado ao configurar endpoints de webhook
Passo 3: Configure endpoint de webhook do Stripe
- No seu Dashboard do Stripe, vá para Developers > Webhooks
- Clique em Add endpoint
- Configure a URL do endpoint para seu futuro domínio Azion (você atualizará isso após o deploy)
- Selecione os eventos que você quer escutar:
payment_intent.succeeded
payment_method.attached
charge.succeeded
invoice.payment_succeeded
- Quaisquer outros eventos relevantes para sua aplicação
Passo 4: Compile o projeto
Compile sua Edge Function para deployment:
pnpm build
Este comando compila sua Edge Function com suporte TypeScript e a prepara para deployment.
Passo 5: Teste localmente
Antes de fazer o deploy, teste seu manipulador de webhook localmente:
pnpm dev
Isso inicia um servidor de desenvolvimento local onde você pode testar o processamento de webhooks.
Entendendo a verificação de webhook
Verificação de assinatura
Webhooks do Stripe incluem um cabeçalho de assinatura que você deve verificar para garantir que o webhook veio do Stripe:
import crypto from 'crypto';
function verifyStripeSignature(payload, signature, secret) { const elements = signature.split(','); const signatureHash = elements.find(element => element.startsWith('v1='));
if (!signatureHash) { throw new Error('Formato de assinatura inválido'); }
const expectedHash = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');
const actualHash = signatureHash.split('=')[1];
if (expectedHash !== actualHash) { throw new Error('Assinatura de webhook inválida'); }
return true;}
Manipulação de eventos de webhook
A Edge Function processa diferentes eventos do Stripe:
async function handleWebhookEvent(event) { switch (event.type) { case 'payment_intent.succeeded': await handlePaymentSuccess(event.data.object); break; case 'payment_intent.payment_failed': await handlePaymentFailure(event.data.object); break; case 'charge.succeeded': await handleChargeSuccess(event.data.object); break; case 'invoice.payment_succeeded': await handleInvoicePayment(event.data.object); break; default: console.log(`Tipo de evento não manipulado: ${event.type}`); }}
Deploy na Azion
Passo 1: Autentique-se na Azion
- Faça login na sua conta Azion via CLI:
azion login
- Siga os prompts de autenticação para conectar sua CLI com sua conta Azion.
Passo 2: Crie secrets para credenciais do Stripe
Para segurança, armazene suas credenciais do Stripe como secrets:
azion create secret STRIPE_SECRET_KEYazion create secret STRIPE_WEBHOOK_SECRET
Quando solicitado, digite suas respectivas credenciais do Stripe. Isso garante que seus dados sensíveis sejam criptografados e seguros.
Passo 3: Faça o deploy da Edge Function
Faça o deploy de seu manipulador de webhook na rede edge da Azion:
azion deploy
O processo de deploy irá:
- Fazer upload do código da sua Edge Function
- Configurar a edge application
- Configurar as regras de roteamento necessárias
- Configurar variáveis de ambiente e secrets
- Fornecer um domínio único
Passo 4: Atualize a configuração de webhook do Stripe
- Após o deploy, você receberá um domínio como
https://xxxxxxx.map.azionedge.net
- Vá para seu Dashboard do Stripe > Developers > Webhooks
- Edite seu endpoint de webhook
- Atualize a URL para
https://xxxxxxx.map.azionedge.net/webhook
- Salve as alterações
Passo 5: Teste entrega de webhook
- Dispare eventos de teste no Dashboard do Stripe
- Monitore entrega e respostas de webhook
- Verifique logs da Edge Function para confirmação de processamento
Eventos de webhook suportados
Eventos de pagamento
- payment_intent.succeeded: Pagamento completado com sucesso
- payment_intent.payment_failed: Tentativa de pagamento falhou
- payment_intent.canceled: Pagamento foi cancelado
Eventos de cobrança
- charge.succeeded: Cobrança completada com sucesso
- charge.failed: Tentativa de cobrança falhou
- charge.refunded: Cobrança foi reembolsada
Eventos de fatura
- invoice.payment_succeeded: Pagamento de fatura completado
- invoice.payment_failed: Pagamento de fatura falhou
- invoice.created: Nova fatura criada
Eventos de cliente
- customer.created: Novo cliente registrado
- customer.updated: Informações do cliente atualizadas
- customer.deleted: Conta do cliente excluída
Exemplos de implementação
Manipulador de sucesso de pagamento
async function handlePaymentSuccess(paymentIntent) { const { id, amount, currency, customer } = paymentIntent;
// Atualizar status do pedido no seu banco de dados await updateOrderStatus(paymentIntent.metadata.order_id, 'paid');
// Enviar email de confirmação await sendPaymentConfirmation(customer, amount, currency);
// Disparar processo de fulfillment await triggerFulfillment(paymentIntent.metadata.order_id);
console.log(`Pagamento bem-sucedido: ${id} por ${amount} ${currency}`);}
Manipulação de assinatura
async function handleSubscriptionEvent(subscription) { const { id, customer, status, current_period_end } = subscription;
switch (status) { case 'active': await activateSubscription(customer, id); break; case 'canceled': await cancelSubscription(customer, id); break; case 'past_due': await handlePastDueSubscription(customer, id); break; }
// Atualizar registro do cliente await updateCustomerSubscription(customer, { subscription_id: id, status, next_billing_date: current_period_end });}
Processamento de reembolso
async function handleRefund(charge) { const { id, amount, currency, refunded } = charge;
if (refunded) { // Processar reembolso no seu sistema await processRefund({ charge_id: id, amount, currency, order_id: charge.metadata.order_id });
// Notificar cliente await sendRefundNotification(charge.customer, amount, currency);
console.log(`Reembolso processado: ${id} por ${amount} ${currency}`); }}
Testando seu manipulador de webhook
Passo 1: Use Stripe CLI para teste local
- Instale Stripe CLI
- Encaminhe webhooks para seu servidor de desenvolvimento local:
stripe listen --forward-to localhost:3000/webhook
- Dispare eventos de teste:
stripe trigger payment_intent.succeededstripe trigger charge.succeededstripe trigger invoice.payment_succeeded
Passo 2: Teste em produção
- Use Dashboard do Stripe para enviar webhooks de teste
- Monitore entrega de webhook e tentativas de retry
- Verifique códigos de resposta e tempos de processamento
- Verifique precisão de manipulação de eventos
Passo 3: Teste de tratamento de erros
- Teste com assinaturas inválidas
- Teste com payloads malformados
- Teste cenários de timeout
- Verifique mecanismos de retry
Melhores práticas de segurança
Verificação de webhook
- Sempre verifique assinaturas: Nunca processe webhooks não verificados
- Use HTTPS: Certifique-se de que todos os endpoints de webhook usem HTTPS
- Valide payload: Verifique estrutura do evento e campos obrigatórios
- Implemente proteção contra replay: Rastreie IDs de eventos processados
Gerenciamento de secrets
- Use secrets da Azion: Armazene credenciais de forma segura
- Rotacione secrets regularmente: Atualize secrets de webhook periodicamente
- Limite acesso: Restrinja acesso a secrets às funções necessárias
- Monitore uso: Rastreie acesso e uso de secrets
Tratamento de erros
async function processWebhook(request) { try { const payload = await request.text(); const signature = request.headers.get('stripe-signature');
// Verificar assinatura do webhook verifyStripeSignature(payload, signature, STRIPE_WEBHOOK_SECRET);
// Analisar evento const event = JSON.parse(payload);
// Processar evento await handleWebhookEvent(event);
return new Response('OK', { status: 200 }); } catch (error) { console.error('Erro de webhook:', error); return new Response('Error', { status: 400 }); }}
Monitoramento e logging
Logging de eventos
function logWebhookEvent(event, status, processingTime) { console.log({ event_id: event.id, event_type: event.type, status, processing_time: processingTime, timestamp: new Date().toISOString() });}
Monitoramento de performance
- Tempos de resposta: Monitore velocidade de processamento de webhook
- Taxas de sucesso: Rastreie processamento bem-sucedido vs falho
- Padrões de erro: Identifique cenários comuns de falha
- Frequência de retry: Monitore tentativas de retry de webhook
Solução de problemas
Problemas comuns e soluções
- Falhas de verificação de assinatura: Verifique configuração de secret do webhook
- Erros de timeout: Otimize lógica de processamento para velocidade
- Processamento duplicado: Implemente verificações de idempotência
- Eventos perdidos: Verifique configuração do endpoint de webhook
Dicas de debugging
- Habilite logging detalhado: Registre todos os eventos de webhook e etapas de processamento
- Use Dashboard do Stripe: Monitore tentativas de entrega de webhook
- Teste localmente: Use Stripe CLI para debugging local
- Verifique assinaturas: Verifique cálculo de assinatura de webhook
Recursos avançados
Manipulação de idempotência
const processedEvents = new Set();
async function processWebhookWithIdempotency(event) { if (processedEvents.has(event.id)) { console.log(`Evento ${event.id} já processado`); return; }
await handleWebhookEvent(event); processedEvents.add(event.id);}
Processamento em lote
async function processBatchEvents(events) { const batchSize = 10; for (let i = 0; i < events.length; i += batchSize) { const batch = events.slice(i, i + batchSize); await Promise.all(batch.map(event => handleWebhookEvent(event))); }}
Próximos passos
- Implemente logging e monitoramento abrangente de eventos
- Adicione funcionalidade de replay de webhook para eventos falhados
- Integre com seu sistema de processamento de pagamentos existente
- Implemente mecanismos avançados de detecção de fraude
- Dimensione processamento de webhook para cenários de alto volume