resend.emails.send por una llamada a SendGrid, Postmark, Amazon SES o tu propio relay SMTP.- Crear un entitlement de crédito personalizado para correos en el dashboard.
- Vincular créditos a un plan de suscripción y a un producto de recarga de compra única.
- Enviar correos mediante Resend y descontar un crédito por envío con una entrada en el ledger.
- Leer el saldo de créditos actualizado de un cliente desde tu frontend.
- Verificar los webhooks de Dodo Payments y gestionar
credit.balance_lowpara avisar a los clientes antes de que su saldo llegue a cero.
Lo que vamos a crear
MailKit vende dos productos:- Una cuenta de Dodo Payments. Crea todo en modo de prueba.
- Una cuenta gratuita de Resend y una API key.
- Node.js 22 o posterior y conocimientos prácticos de TypeScript.
Paso 1: Crea tu entitlement de crédito para correos
El entitlement de crédito define la unidad que vende MailKit: un envío de correo.
The Credits tab under Products lists all your credit entitlements.
Open the Credits Section
- Inicia sesión en el dashboard de Dodo Payments.
- Haz clic en Products en la barra lateral.
- Selecciona la pestaña Credits.
- Haz clic en Create Credit.
Configure the Credit Unit
Email CreditsCredit Type: Custom UnitUnit Name: emailDefine Precision: 0. Un correo es una unidad entera, por lo que el saldo nunca necesita decimales.Credit Expiry: 30 days. Los créditos no utilizados caducan 30 días después de emitirse.Leave the Other Defaults
Save and Copy the Credit ID
cde_. El backend lo usa para leer saldos y crear entradas en el ledger.Email Credits está listo. A continuación, crea los productos que lo conceden a los clientes.Paso 2: Crea el plan y el paquete de recarga
Crea dos productos que vinculen el mismo entitlementEmail Credits: un plan de Subscription que concede 5.000 correos en cada ciclo de facturación y una recarga One Time que añade otros 5.000 bajo demanda.
Plan MailKit ($19/mes, 5.000 correos)
Create the Subscription
- Ve a Products y haz clic en Add Product.
- Introduce los detalles del producto:
MailKit PlanDescription: 5,000 transactional emails per month.- En Pricing Type, selecciona Subscription.
- Define el precio recurrente:
19.00Repeat payment every: 1 mesCurrency: USDAttach the Email Credit Entitlement
Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold (%): 20. Dodo Payments envía credit.balance_low cuando el saldo cae por debajo del 20 % de los créditos emitidos por ciclo, es decir, 1.000 correos.Import Default Credit Settings: activado, para que el producto use la caducidad de 30 días del Paso 1.Añade el crédito al producto y, después, guarda el producto. Copia el ID del producto, que comienza por pdt_.Paquete de recarga ($9 por compra única, 5.000 correos)
Create a One-Time Product
- Ve a Products y haz clic en Add Product.
- Introduce los detalles del producto:
Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance.- En Pricing Type, selecciona One Time.
- Define el precio:
9.00Currency: USDAttach the Credit Grant
- Select credits:
Email Credits - No of credits issued:
5000
Paso 3: Configura el backend
Crea el servidor Express que genere checkouts, envíe correos, lea saldos y reciba webhooks.Initialize the Project
package.json:Configure Environment Variables
.env con una API key de modo de prueba de Developer → API Keys y los IDs de los Pasos 1 y 2:DODO_PAYMENTS_WEBHOOK_KEY en el Paso 4, después de crear el endpoint del webhook. Crea la API key de Resend en resend.com/api-keys.Build the Server
server.ts en la raíz del proyecto. El servidor expone cinco rutas: checkout de suscripción, checkout de recarga, lectura de saldo, envío y receptor del webhook.Add a Demo UI
public/index.html. Llama a cada ruta desde un formulario sencillo para que puedas probar el flujo en un navegador:Paso 4: Conecta el endpoint del webhook
El eventocredit.balance_low permite avisar a los clientes antes de que se queden sin créditos. Sin él, un cliente detectaría el problema cuando un correo no pudiera enviarse.
Expose Your Local Server
https://1234abcd.ngrok-free.app.Register the Endpoint in Dodo Payments
- Ve a Developer → Webhooks y haz clic en Add endpoint.
- Introduce la URL
https://1234abcd.ngrok-free.app/webhooks/dodousando el host de tu propio túnel. - Selecciona los eventos
credit.added,credit.balance_lowycredit.rolled_over. - Haz clic en Create endpoint.
- Copia el signing secret de la pestaña Overview del endpoint en
.envcomoDODO_PAYMENTS_WEBHOOK_KEY. - Reinicia el servidor.
Paso 5: Prueba el flujo completo
Start the Server
MailKit running on http://localhost:3000. Abre esa URL en tu navegador.Subscribe a Test Customer
- En la sección 1, introduce una dirección de correo y un nombre de prueba, y haz clic en Get checkout link.
- Abre el enlace y completa el checkout con una test card.
- En el dashboard, ve a Customers y copia el ID del nuevo cliente, que comienza por
cus_.
Send an Email
- Pega el ID del cliente en la sección 3.
- Deja To establecido en
delivered@resend.dev, una dirección de prueba de Resend que acepta todos los mensajes. - Haz clic en Send.
Trigger the Low-Balance Webhook
- Abre el cliente en Customers, selecciona la pestaña Credits y elige Email Credits.
- Haz clic en Apply Credit/Debit, selecciona Debit e introduce
4000. El saldo ahora es exactamente 1.000, por lo que todavía no está por debajo del umbral. - Envía otro correo desde la demo. El saldo baja a 999.
Buy a Top-Up Pack
- Pega el ID del cliente en la sección 4.
- Haz clic en Buy 5,000 emails y completa el checkout de prueba.
- Actualiza el saldo. Aumenta en 5.000.
credit.added con transaction_type: "credit_added". El grant que hay detrás tiene source_type: one_time, que puedes leer de nuevo con la API List Customer Grants. Los créditos de recarga se suman a los créditos de la suscripción. Los débitos se extraen del grant que caduca primero y del grant más antiguo cuando dos caducan al mismo tiempo.Test the Hard Stop
402:402 es la aplicación de la política de tu aplicación. Trata la API de saldo de Dodo Payments como la fuente de verdad y no almacenes en caché el saldo en el cliente.Solución de problemas
Webhook signature verification fails (401)
Webhook signature verification fails (401)
express.json() reemplaza el cuerpo por un objeto analizado, por lo que la verificación falla. Registra /webhooks/dodo con express.raw({ type: 'application/json' }) encima de la línea app.use(express.json()). Después, comprueba que DODO_PAYMENTS_WEBHOOK_KEY coincida con el signing secret de la pestaña Overview del endpoint.Balance is 0, customer not found, or credits don't deduct
Balance is 0, customer not found, or credits don't deduct
- El cliente completó el checkout. Los créditos se emiten cuando el pago se completa correctamente, no cuando se crea la sesión de checkout.
CREDIT_ENTITLEMENT_IDen.envcoincide con el crédito vinculado al producto. Las llamadas de saldo y ledger usan este ID, por lo que una discrepancia lee o descuenta de un crédito diferente.- El
customer_idque pasas es el ID de cliente de Dodo Payments (comienza porcus_), no un ID de tu propia base de datos.
Resend rejects the recipient
Resend rejects the recipient
onboarding@resend.dev solo entrega mensajes a la dirección de correo de tu cuenta de Resend o a delivered@resend.dev. Para enviar mensajes a cualquier otra persona, verifica un dominio y usa una dirección from en ese dominio.Lo que has creado
One Reusable Credit Unit
Email Credits, definido una sola vez y vinculado tanto al plan de suscripción como al paquete de recarga.Subscription with Prepaid Allowance
Top-Up Pack
Direct Ledger Debits
createLedgerEntry después de cada envío, sin medidor ni retraso de agregación. El ID del mensaje de Resend como clave de idempotencia evita un segundo débito para el mismo envío.