Pagos · modules/billing

Scaffold de adapter

Stripe,
detrás de un solo contrato.

UseDeploy modela el billing como un único port IPaymentProvider. Stripe es uno de los adapters que se enchufa ahí — seleccionado por una env var, compartiendo los mismos tipos normalizados que MercadoPago y Polar, así que cambiar de proveedor es un cambio de un solo archivo.

Qué viene listo y qué completás vos

Honestidad primero: el adapter de Stripe es un scaffold, no una integración llave en mano. La selección de proveedor, la validación de config y el path del customer portal están cableados — createCustomerPortalLink importa el SDK de Stripe de forma lazy y llama a billingPortal.sessions.create. La creación de la sesión de checkout y el parseo de webhooks son stubs tipados con las llamadas exactas al SDK escritas en los comentarios. ¿Por qué scaffold y no terminarlo? Porque la base del boilerplate no trae el paquete stripe como dependencia. Lo sumás, completás los dos métodos contra la forma que ya está fijada, y cada consumidor del contrato de billing sigue funcionando sin cambios. El compromiso que asumimos ahora es la interfaz — para que tu código nunca se acople a las particularidades de Stripe.

Una env var selecciona el proveedor

El composition root construye exactamente un proveedor de pago a partir de PAYMENT_PROVIDER. Ponelo en stripe y pasá los dos secrets; la factory los valida al arrancar y lanza un error claro si falta alguno.

apps/server/.env
 1  PAYMENT_PROVIDER=stripe
 2  STRIPE_SECRET_KEY=sk_live_...
 3  STRIPE_WEBHOOK_SECRET=whsec_...
 4  
 5  # Then add the SDK the scaffold expects:
 6  #   bun add stripe   (in apps/server)

El contrato de billing en el que Stripe se enchufa

Customer portal — cableado

createCustomerPortalLink importa el SDK de Stripe de forma lazy y devuelve una URL de billing portal alojado. Cero costo de SDK para deployments que usan otro proveedor.

Checkout — scaffold

createCheckoutSession devuelve un "aún no implementado" tipado hasta que cablees stripe.checkout.sessions.create contra la forma de input fijada.

Webhooks — scaffold

parseWebhook está como stub con la llamada exacta a hacer: stripe.webhooks.constructEvent(rawBody, sig, secret) mapeada a un BillingEvent normalizado.

Tipos agnósticos del proveedor

Los tipos de retorno Result<T, DomainError> son idénticos entre Stripe, MercadoPago y Polar, así que la capa de aplicación nunca ramifica según el proveedor.

Referencia de configuración

Variables de entorno

  • PAYMENT_PROVIDERrequerida

    Set to stripe

  • STRIPE_SECRET_KEYrequerida
  • STRIPE_WEBHOOK_SECRETrequerida

Dónde vive

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

Construí el billing sobre un contrato, no sobre un proveedor.

Shippeá con Stripe, MercadoPago o Polar detrás del mismo port tipado — y nunca reescribas tu app para cambiar.