resend.emails.send bằng lệnh gọi đến SendGrid, Postmark, Amazon SES hoặc SMTP relay của riêng bạn.- Tạo entitlement credit tùy chỉnh cho email trong dashboard.
- Gắn credit vào một gói subscription và một sản phẩm top-up mua một lần.
- Gửi email qua Resend và trừ một credit cho mỗi lần gửi bằng một ledger entry.
- Đọc số dư credit hiện tại của khách hàng từ frontend.
- Xác minh webhook của Dodo Payments và xử lý
credit.balance_lowđể cảnh báo khách hàng trước khi số dư về không.
Những gì chúng ta sẽ xây dựng
MailKit bán hai sản phẩm:- Một tài khoản Dodo Payments. Hãy xây dựng mọi thứ ở test mode.
- Một tài khoản Resend miễn phí và API key.
- Node.js 22 trở lên và kiến thức thực tế về TypeScript.
Bước 1: Tạo Email Credit Entitlement
Credit entitlement định nghĩa đơn vị mà MailKit bán: một lần gửi email.
The Credits tab under Products lists all your credit entitlements.
Open the Credits Section
- Đăng nhập vào dashboard Dodo Payments.
- Nhấp Products trong thanh bên.
- Chọn tab Credits.
- Nhấp Create Credit.
Configure the Credit Unit
Email CreditsCredit Type: Custom UnitUnit Name: emailDefine Precision: 0. Email là một đơn vị nguyên, vì vậy số dư không bao giờ cần phần thập phân.Credit Expiry: 30 days. Credit chưa sử dụng sẽ hết hạn sau 30 ngày kể từ khi được cấp.Leave the Other Defaults
Save and Copy the Credit ID
cde_. Backend sử dụng ID này để đọc số dư và tạo ledger entry.Email Credits đã sẵn sàng. Tiếp theo, hãy tạo các sản phẩm cấp entitlement này cho khách hàng.Bước 2: Tạo Plan và Top-Up Pack
Tạo hai sản phẩm cùng gắn entitlementEmail Credits: một plan Subscription cấp 5.000 email trong mỗi chu kỳ thanh toán và một gói top-up One Time cộng thêm 5.000 email theo nhu cầu.
Gói MailKit ($19/tháng, 5.000 Email)
Create the Subscription
- Đi đến Products và nhấp Add Product.
- Nhập thông tin sản phẩm:
MailKit PlanDescription: 5,000 transactional emails per month.- Trong Pricing Type, chọn Subscription.
- Đặt giá định kỳ:
19.00Repeat payment every: 1 thángCurrency: USDAttach the Email Credit Entitlement
Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold (%): 20. Dodo Payments gửi credit.balance_low khi số dư giảm xuống dưới 20% số credit được cấp mỗi chu kỳ, tương đương 1.000 email.Import Default Credit Settings: bật để sản phẩm sử dụng thời hạn 30 ngày từ Bước 1.Thêm credit vào sản phẩm, sau đó lưu sản phẩm. Sao chép product ID, bắt đầu bằng pdt_.Gói Top-Up ($9 một lần, 5.000 Email)
Create a One-Time Product
- Đi đến Products và nhấp Add Product.
- Nhập thông tin sản phẩm:
Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance.- Trong Pricing Type, chọn One Time.
- Đặt giá:
9.00Currency: USDAttach the Credit Grant
- Select credits:
Email Credits - No of credits issued:
5000
Bước 3: Thiết lập Backend
Xây dựng Express server để tạo checkout, gửi email, đọc số dư và nhận webhook.Initialize the Project
package.json:Configure Environment Variables
.env bằng test mode API key từ Developer → API Keys và các ID từ Bước 1 và 2:DODO_PAYMENTS_WEBHOOK_KEY ở Bước 4, sau khi tạo webhook endpoint. Tạo Resend API key tại resend.com/api-keys.Build the Server
server.ts ở thư mục gốc của project. Server cung cấp năm route: checkout subscription, checkout top-up, đọc số dư, gửi email và webhook receiver.Add a Demo UI
public/index.html. File này gọi từng route từ một form đơn giản để bạn có thể kiểm thử quy trình trong trình duyệt:Bước 4: Kết nối Webhook Endpoint
Eventcredit.balance_low cho phép bạn cảnh báo khách hàng trước khi họ hết credit. Nếu không có event này, khách hàng chỉ nhận ra vấn đề khi email không gửi được.
Expose Your Local Server
https://1234abcd.ngrok-free.app.Register the Endpoint in Dodo Payments
- Đi đến Developer → Webhooks và nhấp Add endpoint.
- Nhập URL
https://1234abcd.ngrok-free.app/webhooks/dodo, sử dụng tunnel host của bạn. - Chọn các event
credit.added,credit.balance_lowvàcredit.rolled_over. - Nhấp Create endpoint.
- Sao chép signing secret từ tab Overview của endpoint vào
.envdưới dạngDODO_PAYMENTS_WEBHOOK_KEY. - Khởi động lại server.
Bước 5: Kiểm thử Toàn bộ Quy trình
Start the Server
MailKit running on http://localhost:3000. Mở URL đó trong trình duyệt.Subscribe a Test Customer
- Trong phần 1, nhập địa chỉ email và tên kiểm thử, sau đó nhấp Get checkout link.
- Mở link và hoàn tất checkout bằng test card.
- Trong dashboard, đi đến Customers và sao chép ID của customer mới, bắt đầu bằng
cus_.
Send an Email
- Dán customer ID vào phần 3.
- Giữ To ở giá trị
delivered@resend.dev, một địa chỉ kiểm thử Resend chấp nhận mọi message. - Nhấp Send.
Trigger the Low-Balance Webhook
- Mở customer trong Customers, chọn tab Credits và chọn Email Credits.
- Nhấp Apply Credit/Debit, chọn Debit và nhập
4000. Số dư lúc này chính xác là 1.000, vẫn chưa thấp hơn ngưỡng. - Gửi thêm một email từ demo. Số dư giảm xuống 999.
Buy a Top-Up Pack
- Dán customer ID vào phần 4.
- Nhấp Buy 5,000 emails và hoàn tất test checkout.
- Làm mới số dư. Số dư tăng thêm 5.000.
credit.added với transaction_type: "credit_added". Grant tương ứng có source_type: one_time, bạn có thể đọc lại bằng API List Customer Grants. Credit top-up được cộng vào credit subscription. Debit được trừ từ grant hết hạn trước, và từ grant cũ nhất khi hai grant hết hạn cùng lúc.Test the Hard Stop
402:402 đó là cơ chế enforcement của ứng dụng. Hãy xem balance API của Dodo Payments là nguồn dữ liệu chính xác và không cache số dư trên client.Khắc phục sự cố
Webhook signature verification fails (401)
Webhook signature verification fails (401)
express.json() thay thế body bằng parsed object, nên việc xác minh thất bại. Đăng ký /webhooks/dodo với express.raw({ type: 'application/json' }) bên trên dòng app.use(express.json()). Sau đó kiểm tra DODO_PAYMENTS_WEBHOOK_KEY có khớp với signing secret trong tab Overview của endpoint hay không.Balance is 0, customer not found, or credits don't deduct
Balance is 0, customer not found, or credits don't deduct
- Customer đã hoàn tất checkout. Credit được cấp khi thanh toán thành công, không phải khi checkout session được tạo.
CREDIT_ENTITLEMENT_IDtrong.envkhớp với credit được gắn vào sản phẩm. Các lệnh gọi balance và ledger sử dụng ID này, vì vậy nếu không khớp, bạn sẽ đọc hoặc trừ một credit khác.customer_idbạn truyền vào là Dodo Payments customer ID (bắt đầu bằngcus_), không phải ID từ database riêng của bạn.
Resend rejects the recipient
Resend rejects the recipient
onboarding@resend.dev chỉ gửi đến địa chỉ email trên tài khoản Resend của bạn hoặc đến delivered@resend.dev. Để gửi đến người khác, xác minh domain và sử dụng địa chỉ from trên domain đó.Những gì Bạn đã Xây dựng
One Reusable Credit Unit
Email Credits, được định nghĩa một lần và gắn vào cả subscription plan lẫn top-up pack.Subscription with Prepaid Allowance
Top-Up Pack
Direct Ledger Debits
createLedgerEntry sau mỗi lần gửi, không cần meter và không có độ trễ tổng hợp. Resend message ID được dùng làm idempotency key để ngăn việc trừ lần thứ hai cho cùng một lần gửi.