Skip to main content
若要让您的编码代理编写集成,请安装 Dodo Agent Plugin。它会将 Dodo Payments skills 和 MCP servers 添加到 Claude Code、Codex CLI、Cursor、VS Code / GitHub Copilot、Kiro 和 OpenCode。
您将构建 MailKit,这是一个让客户预付电子邮件额度的事务性电子邮件服务。月度计划在每个计费周期提供 5,000 封邮件。额度不足的客户可以购买充值包,而不必等待下一个周期。每发送一封邮件扣除一个额度。
本教程使用 Resend 作为电子邮件提供商。其免费层级(每月 3,000 封邮件)足以覆盖完整流程的构建和测试。此计费模式适用于任何提供商:将 resend.emails.send 替换为对 SendGrid、Postmark、Amazon SES 或您自己的 SMTP relay 的调用。
完成后,您将了解如何:
  • 在 dashboard 中创建用于电子邮件的自定义额度权益。
  • 将额度附加到订阅计划和一次性充值产品。
  • 通过 Resend 发送电子邮件,并在 ledger 中记录每次发送扣除一个额度。
  • 从前端读取客户的实时额度余额。
  • 验证 Dodo Payments webhooks,并处理 credit.balance_low,在客户余额归零前发出提醒。

What We’re Building

MailKit 销售两种产品: 计量单位是 一封电子邮件 = 一个额度。客户不需要理解 tokens、批次或加权单位。他们看到的是“本月还剩 4,231 封邮件”。 开始前,您需要:
  • 一个 Dodo Payments 账户。请在 test mode 中完成所有构建工作。
  • 一个免费的 Resend 账户和 API key。
  • Node.js 22 或更高版本,以及 TypeScript 基础知识。

第 1 步:创建电子邮件额度权益

额度权益定义了 MailKit 销售的单位:发送一封电子邮件。
Credits tab under Products, listing the business's credit entitlements

The Credits tab under Products lists all your credit entitlements.

1

Open the Credits Section

  1. 登录 Dodo Payments dashboard。
  2. 点击侧边栏中的 Products。
  3. 选择 Credits 标签页。
  4. 点击 Create Credit。
2

Configure the Credit Unit

输入以下值:Credit Name:Email CreditsCredit Type:Custom UnitUnit Name:emailDefine Precision:0。电子邮件是整数单位,因此余额不需要小数。Credit Expiry:30 days。未使用的额度会在发放 30 天后过期。
创建额度后无法更改精度。对于电子邮件、消息或会话等离散单位,请使用 0。
3

Leave the Other Defaults

为使额度流程保持简洁,本教程关闭了 rollover 和 overage。之后可以重新开启,既可以在额度上开启,也可以在每个产品的额度附加设置中开启。
4

Save and Copy the Credit ID

点击 Create Credit。打开该额度并复制其 ID,该 ID 以 cde_ 开头。后端会使用它读取余额并创建 ledger entries。
Email Credits 权益已准备就绪。接下来,创建向客户发放该权益的产品。

第 2 步:创建计划和充值包

创建两个附加同一 Email Credits 权益的产品:一个每个计费周期提供 5,000 封邮件的 Subscription 计划,以及一个按需额外增加 5,000 封邮件的 One Time 充值产品。
本教程使用 ledger entries 扣除额度,而不是 usage meters。API call 返回时会应用 ledger debit,无需设置 meter,适用于每次用户操作恰好消耗一个额度的场景。若要根据摄取的 usage events 自动扣除额度(适用于 tokens 或处理的 megabytes 等加权单位),请参阅 Credit-Based Billing 指南中的 Usage Billing with Credits。

MailKit Plan($19/月,5,000 封邮件)

1

Create the Subscription

  1. 前往 Products 并点击 Add Product。
  2. 输入产品详细信息:
Product Name:MailKit PlanDescription:5,000 transactional emails per month.
  1. 在 Pricing Type 下选择 Subscription。
  2. 设置 recurring price:
Price:19.00Repeat payment every:1 月Currency:USD
2

Attach the Email Credit Entitlement

在 Entitlements 部分,点击 Credits 旁边的 Attach,并配置:Select credits:Email CreditsCredits issued per billing cycle:5000Low Balance Threshold (%):20。当余额低于每个周期发放额度的 20%(即 1,000 封邮件)时,Dodo Payments 会发送 credit.balance_low。Import Default Credit Settings:开启,这样产品会使用第 1 步中设置的 30 天过期时间。将额度添加到产品,然后保存产品。复制产品 ID,该 ID 以 pdt_ 开头。
计划:$19/月,每个计费周期发放 5,000 封邮件。

Top-Up Pack($9 一次性支付,5,000 封邮件)

1

Create a One-Time Product

  1. 前往 Products 并点击 Add Product。
  2. 输入产品详细信息:
Product Name:Email Top-Up PackDescription:Add 5,000 emails to your MailKit balance.
  1. 在 Pricing Type 下选择 One Time。
  2. 设置价格:
Price:9.00Currency:USD
2

Attach the Credit Grant

在 Entitlements 部分,点击 Credits 旁边的 Attach,并配置:
  • Select credits:Email Credits
  • No of credits issued:5000
一次性产品会发放具有独立过期时间的额度:从购买日起 30 天后过期,这是第 1 步中设置的默认值。充值额度会添加到订阅额度中,不会替换订阅额度。
保存产品并复制其 ID。
Top-Up Pack:$9 购买 5,000 封邮件,支付成功后添加到余额。

第 3 步:设置后端

构建 Express server,用于创建 checkouts、发送电子邮件、读取余额和接收 webhooks。
1

Initialize the Project

将 dev script 添加到 package.json:
tsx 可直接运行 TypeScript,无需 build step 或 tsconfig.json。用于 production 时,添加 tsconfig.json 和 build script。
2

Configure Environment Variables

使用 Developer → API Keys 中的 test mode API key 以及第 1、2 步中的 ID 创建 .env:
.env
创建 webhook endpoint 后,在第 4 步中填写 DODO_PAYMENTS_WEBHOOK_KEY。请在 resend.com/api-keys 创建 Resend API key。
在第一次提交前,将 .env 添加到 .gitignore。切勿提交 API keys。
3

Build the Server

在项目根目录创建 server.ts。服务器提供五个 routes:subscribe checkout、top-up checkout、balance read、send 和 webhook receiver。
webhook route 必须接收原始 request body。express.json() 会将 body 替换为已解析的对象,而 signature verification 需要 Dodo Payments 签名时使用的精确字节。保留 /webhooks/dodo route,并将其与 express.raw() 放在 app.use(express.json()) 行之前。
后端已准备就绪:subscribe、top-up、balance、send 以及 webhook handler。
4

Add a Demo UI

创建 public/index.html。它通过一个简单表单调用每个 route,以便您在浏览器中测试流程:

第 4 步:连接 Webhook Endpoint

credit.balance_low event 可让您在客户额度用尽前发出提醒。没有它,客户要等到电子邮件发送失败后才会首次发现问题。
1

Expose Your Local Server

Webhooks 需要 public URL。开发期间,可以使用 ngrok 或其他 tunnel:
复制 HTTPS forwarding URL,例如 https://1234abcd.ngrok-free.app。
2

Register the Endpoint in Dodo Payments

  1. 前往 Developer → Webhooks 并点击 Add endpoint。
  2. 输入 URL https://1234abcd.ngrok-free.app/webhooks/dodo,并使用您自己的 tunnel host。
  3. 选择 events credit.added、credit.balance_low 和 credit.rolled_over。
  4. 点击 Create endpoint。
  5. 从 endpoint 的 Overview 标签页复制 signing secret,并将其作为 DODO_PAYMENTS_WEBHOOK_KEY 填入 .env。
  6. 重启 server。

第 5 步:测试完整流程

1

Start the Server

服务器会记录 MailKit running on http://localhost:3000。在浏览器中打开该 URL。
2

Subscribe a Test Customer

  1. 在第 1 部分输入测试电子邮件地址和姓名,然后点击 Get checkout link。
  2. 打开链接,并使用测试卡完成 checkout。
  3. 在 dashboard 中前往 Customers,复制新客户的 ID,该 ID 以 cus_ 开头。
客户余额中有 5,000 封邮件。要确认这一点,请在 Customers 中打开该客户并选择 Credits 标签页。
3

Send an Email

  1. 将客户 ID 粘贴到第 3 部分。
  2. 保持 To 为 delivered@resend.dev,这是一个可接收所有邮件的 Resend test address。
  3. 点击 Send。
页面会显示 Resend message ID。在第 2 部分刷新余额:余额为 4,999。API call 返回后,ledger debit 就会计入余额。
4

Trigger the Low-Balance Webhook

阈值为 20%,即每个周期发放的 5,000 封邮件中的 1,000 封。无需发送 4,000 封邮件即可达到该阈值,您可以在 dashboard 中手动扣除余额:
  1. 在 Customers 中打开客户,选择 Credits 标签页,然后选择 Email Credits。
  2. 点击 Apply Credit/Debit,选择 Debit,并输入 4000。此时余额正好为 1,000,尚未低于阈值。
  3. 从 demo 再发送一封电子邮件。余额降至 999。
webhook 到达后,server 会记录:
server 已接收并验证 webhook。在 production 中,您可以在这里向客户发送电子邮件,或显示 in-app banner。
5

Buy a Top-Up Pack

  1. 将客户 ID 粘贴到第 4 部分。
  2. 点击 Buy 5,000 emails 并完成测试 checkout。
  3. 刷新余额。余额增加 5,000。
Dodo Payments 会发送一个包含 transaction_type: "credit_added" 的 credit.added event。其背后的 grant 具有 source_type: one_time,您可以通过 List Customer Grants API 读取。充值额度会添加到订阅额度中。扣除额度时,会优先使用最早过期的 grant;如果两个 grant 同时过期,则使用较早创建的 grant。
6

Test the Hard Stop

在 dashboard 中将余额扣至零,然后尝试再发送一封电子邮件。server 会以 402 响应:
402 是应用的 enforcement。请将 Dodo Payments balance API 视为事实来源,不要在 client 上缓存余额。

故障排除

签名覆盖原始 HTTP body。express.json() 会将 body 替换为已解析的对象,因此 verification 会失败。将 /webhooks/dodo 与 express.raw({ type: 'application/json' }) 一起注册,并置于 app.use(express.json()) 行之前。然后检查 DODO_PAYMENTS_WEBHOOK_KEY 是否与 endpoint Overview 标签页中的 signing secret 匹配。
按以下顺序检查三件事:
  1. 客户已完成 checkout。额度会在支付成功时发放,而不是在创建 checkout session 时发放。
  2. .env 中的 CREDIT_ENTITLEMENT_ID 与产品附加的额度匹配。余额和 ledger calls 使用此 ID,因此不匹配会读取或扣除另一个额度。
  3. 您传入的 customer_id 是 Dodo Payments customer ID(以 cus_ 开头),而不是您自己的 database 中的 ID。
测试 sender onboarding@resend.dev 只会向您 Resend 账户上的电子邮件地址或 delivered@resend.dev 发送邮件。若要发送给其他人,请验证域名,并使用该域名下的 from 地址。

您构建的内容

One Reusable Credit Unit

Email Credits 只定义一次,并附加到订阅计划和充值包。

Subscription with Prepaid Allowance

$19/月,每个计费周期提供 5,000 封邮件。客户清楚付费内容,而您清楚最大成本。

Top-Up Pack

一个一次性产品,在不更改计划的情况下,在订阅额度之上额外提供 5,000 封邮件。

Direct Ledger Debits

每次发送后调用一次 createLedgerEntry,无需 meter,也没有 aggregation delay。将 Resend message ID 作为 idempotency key,可阻止同一发送被重复扣除。

Credit-Based Billing Reference

Rollover、overage modes、ledger management 以及完整的 credit API。
如需帮助,请在 Discord Community 中提问,或发送电子邮件至 support@dodopayments.com。
最后修改于 2026年9月26日