Pagamentos · modules/billing

Adapter pronto para produção

MercadoPago,
conectado do jeito certo.

A maioria dos starters de SaaS em Next.js é Stripe-first. Quando você precisa cobrar em reais ou pesos, colar o MercadoPago no Next.js na mão é onde moram os bugs clássicos — webhooks sem verificação, handlers não idempotentes e um sandbox que briga com você. A UseDeploy entrega o adapter para você herdar o encanamento, não a dor.

A dor que a gente já comeu

Integrar o MercadoPago tem fama, e os fóruns de devs merecem: "de longe essa é a mais complexa e difícil de testar." O webhook assíncrono é onde ele morde — a verdade sobre um pagamento chega depois do redirect, em uma request assinada à parte que você tem que verificar e reconciliar contra o seu próprio banco de dados. O adapter da UseDeploy é uma implementação real e funcional desse fluxo: preferências de Checkout Pro para o redirect, uma checagem HMAC em tempo constante em cada notificação que chega, e um fetch do status do pagamento que mapeia o resultado no mesmo BillingEvent normalizado que qualquer outro provider emite. Você conecta seu access token; o trilho já está construído.

Webhooks assinados, verificados antes de serem confiados

Cada notificação do MercadoPago é verificada contra o manifest x-signature / x-request-id com HMAC-SHA256 e uma comparação em tempo constante antes de buscar o pagamento e mapeá-lo em um BillingEvent. Uma chamada sem assinatura ou adulterada é rejeitada com um 400 — as classes de cobrança dupla e de webhook falsificado ficam fechadas por padrão.

mercado-pago-payment-provider.ts
 1  const manifest = `id:${dataId};request-id:${xRequestId};ts:${ts};`;
 2  const expected = crypto
 3    .createHmac('sha256', this.cfg.webhookSecret)
 4    .update(manifest)
 5    .digest('hex');
 6  
 7  // constant-time comparison — never a naive === on the digest
 8  return crypto.timingSafeEqual(hashBuf, expectedBuf);

O que o adapter faz hoje

Redirect de Checkout Pro

createCheckoutSession faz um POST na API /checkout/preferences e retorna a URL init_point. O modo de pagamento único está ativo; currency_id cobre ARS, BRL, MXN, USD e EUR.

Webhooks assíncronos assinados

parseWebhook verifica a assinatura HMAC, busca /v1/payments/:id, e emite invoice.paid ou invoice.payment_failed no event bus de billing.

Um único contrato tipado

O MercadoPago implementa o mesmo port IPaymentProvider que o Stripe e o Polar — trocar de provider é uma mudança de um único arquivo no composition root.

Event bus durável

Os eventos de billing fluem pelo outbox durável, então um webhook que chega duas vezes ou fora de ordem se reconcilia contra o seu DB em vez de aplicar em dobro.

Catálogo de planos vindo do Prisma

listPlans lê a tabela BillingPlan, então seu pricing vive no seu banco de dados — não hardcoded por provider.

Docs de produto trilíngues

O site Fumadocs entrega páginas reais EN / ES / PT (convenção dot-parser, EN canônico), não só roteamento de locale sobre copy em inglês.

Respostas diretas

Suporta assinaturas recorrentes (preapproval)?+
Ainda não. Em julho de 2026, o adapter do MercadoPago implementa pagamentos únicos de Checkout Pro; o modo assinatura retorna um erro explícito de "ainda não suportado" em vez de cobrar errado em silêncio. O contrato tipado já modela assinaturas, então preapproval é um acréscimo no nível do adapter — Stripe e Polar cobrem o billing recorrente hoje.
Como eu testo sem tocar em produção?+
Você aponta MERCADO_PAGO_ACCESS_TOKEN para suas credenciais de sandbox. Como a seleção de provider é uma única factory guiada por env, alternar entre sandbox e live é uma mudança de config, não de código.
Dá para rodar MercadoPago e Stripe ao mesmo tempo?+
O boilerplate seleciona um PAYMENT_PROVIDER ativo por deployment. Os três adapters vêm na árvore atrás da mesma interface, então você escolhe por ambiente (por exemplo MercadoPago para seu tenant de LATAM, Stripe ou Polar para global).

Referência de configuração

Variáveis de ambiente

  • PAYMENT_PROVIDERobrigatória

    Set to mercado-pago

  • MERCADO_PAGO_ACCESS_TOKENobrigatória
  • MERCADO_PAGO_WEBHOOK_SECRETobrigatória

    HMAC secret for x-signature verification

Onde ele vive

  • apps/server/src/modules/billing/infrastructure/providers/mercado-pago-payment-provider.ts
  • apps/server/src/modules/billing/infrastructure/providers/index.ts

Pare de colar o MercadoPago no Next.js na mão.

Comece sobre uma base onde o checkout, os webhooks assinados e o contrato de billing já estão conectados — e localizados em EN, ES e PT.