resend.emails.send por SendGrid, Postmark, SES ou seu próprio relay SMTP.- Criar um entitlement de crédito personalizado (e-mails) no dashboard
- Associar créditos a um plano de assinatura e a um produto de recarga avulso
- Enviar e-mails reais via Resend e debitar um crédito por envio usando uma entrada no ledger
- Consultar um saldo de créditos atualizado no frontend
- Verificar corretamente os webhooks do Dodo e lidar com
credit.balance_lowpara avisar os clientes antes que o saldo chegue a zero
O que vamos criar
Este é o modelo de preços do MailKit:- Uma conta do Dodo Payments (o modo de teste é suficiente)
- Uma conta gratuita do Resend e uma API key
- Node.js 18+ e familiaridade básica com TypeScript
Etapa 1: crie seu entitlement de crédito de e-mail
O entitlement de crédito define a unidade que sua plataforma vende: neste caso, um envio de e-mail.
The Credits tab under Products lists all your credit entitlements.
Open the Credits section
- Acesse o dashboard do Dodo Payments
- Clique em Products na barra lateral esquerda
- Selecione a aba Credits
- Clique em Create Credit
Configure the credit unit
Email CreditsCredit Type: selecione Custom UnitUnit Name: emailPrecision: 0 (um e-mail é sempre uma unidade inteira; não é possível enviar meio e-mail)Credit Expiry: 30 days (a quantidade de cada ciclo é redefinida)Leave the other defaults as-is
Save and copy the credit ID
cent_xxxxxxxxxxxx.Email Credits está pronto. Em seguida, criaremos os produtos que concedem créditos aos clientes.Etapa 2: crie o plano e o pacote de recarga
Você criará dois produtos: um plano recorrente de Subscription e uma recarga de Single Payment. O plano concede 5.000 e-mails a cada ciclo; a recarga adiciona outros 5.000 sob demanda. Ambos associam o mesmo entitlementEmail Credits.
Plano MailKit (US$ 19/mês, 5.000 e-mails)
Create the subscription
- Acesse Products → Create Product
- Preencha os detalhes do produto:
MailKit PlanDescription: 5,000 transactional emails per month.- Selecione Subscription como tipo de produto
- Defina o preço recorrente:
19.00Billing Cycle: MonthlyCurrency: USDAttach the email credit entitlement
Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold: 20 (percentual; dispara credit.balance_low quando o saldo fica abaixo de 20% da quantidade do ciclo, ou seja, 1.000 e-mails)Import Default Credit Settings: habilitado (usa a expiração de 30 dias da Etapa 1)Clique em Add to Product e depois em Save para salvar o produto. Copie o ID do produto (pdt_xxxxxxxxxxxx).Pacote de recarga (US$ 9 avulso, 5.000 e-mails)
Create a one-time product
- Acesse Products → Create Product
- Preencha os detalhes do produto:
Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance instantly.- Selecione Single Payment como tipo de produto
- Defina o preço:
9.00Currency: USDAttach the credit grant
- Credit Entitlement:
Email Credits - Credits issued:
5000
Etapa 3: configure o backend
Agora crie o servidor Express que gerenciará o checkout, os envios, as consultas de saldo e os webhooks.Initialize the project
package.json:Configure environment variables
.env:DODO_WEBHOOK_KEY na Etapa 4, depois de criar o endpoint. A API key do Resend vem de resend.com/api-keys.Build the server
server.ts na raiz do projeto:Add a demo UI
public/index.html:Etapa 4: conecte o endpoint de webhook
O eventocredit.balance_low permite avisar os clientes antes que eles fiquem sem créditos. Sem ele, a primeira vez que perceberão o problema será quando um e-mail não conseguir ser enviado.
Expose your local server
https://1234abcd.ngrok-free.app).Register the endpoint in Dodo
- Acesse Developers → Webhooks → Add Endpoint
- URL:
https://1234abcd.ngrok-free.app/webhooks/dodo - Events: assine
credit.added,credit.balance_lowecredit.rolled_over - Salve e copie a signing key para o seu
.envcomoDODO_WEBHOOK_KEY - Reinicie o servidor
Etapa 5: teste o fluxo completo
Start the server
MailKit running on http://localhost:3000. Abra-o no navegador.Subscribe a test customer
- Na seção 1, insira um e-mail e um nome de teste e clique em Get checkout link
- Abra o link e conclua o checkout com um cartão de teste
- Após o pagamento, encontre o
customer_idno dashboard, em Customers
Send a real email
- Cole o
customer_idna seção 3 - Mantenha
todefinido comodelivered@resend.dev(a caixa de entrada sandbox do Resend que aceita tudo) - Clique em Send
Trigger the low-balance webhook
- Acesse Customers → [Customer] → Credits → Email Credits
- Clique em Adjust Balance e debite
4000 - Envie mais um e-mail pela demonstração
Buy a top-up pack
- Cole o
customer_idna seção 4 - Clique em Buy 5,000 emails e conclua o checkout de teste
- Atualize o saldo; ele aumentará em 5.000
credit.added é disparado com grant_source: one_time. A recarga é acumulada sobre os créditos da assinatura; os dois conjuntos são consumidos em ordem FIFO (a concessão não expirada mais antiga primeiro).Test the hard stop
Solução de problemas
Webhook signature verification fails (401)
Webhook signature verification fails (401)
express.json() analisa e serializa novamente o payload, quebrando o HMAC. Certifique-se de que /webhooks/dodo esteja registrado com express.raw({ type: 'application/json' }) acima da linha app.use(express.json()) e que DODO_WEBHOOK_KEY corresponda à signing key exibida na página de detalhes do endpoint.Balance is 0, customer not found, or credits don't deduct
Balance is 0, customer not found, or credits don't deduct
- O cliente concluiu o checkout (os créditos são concedidos após o pagamento bem-sucedido, não na criação da sessão)
CREDIT_ENTITLEMENT_IDno seu.envcorresponde ao crédito associado ao produto (IDs incompatíveis gravam silenciosamente no crédito errado)- O
customer_idque você está enviando veio do Dodo (a tabelacustomersno dashboard), não do seu próprio banco de dados
Resend rejects the recipient
Resend rejects the recipient
onboarding@resend.dev só entrega para o e-mail da sua conta do Resend ou para delivered@resend.dev. Para enviar a qualquer outra pessoa, verifique um domínio e use um endereço from nele.O que você criou
One reusable credit unit
Email Credits, definido uma única vez e associado ao plano de assinatura e ao pacote de recarga.Subscription with prepaid allowance
Top-up pack
Instant ledger debits
createLedgerEntry após cada envio. Sem meter, sem atraso de agregação e idempotente em novas tentativas por meio do ID da mensagem do Resend.