Skip to main content
코딩 에이전트가 통합을 작성하도록 하려면 Dodo Agent Plugin을 설치하세요. 이 플러그인은 Claude Code, Codex CLI, Cursor, VS Code / GitHub Copilot, Kiro, OpenCode에 Dodo Payments skills와 MCP servers를 추가합니다.
MailKit을 구축합니다. MailKit은 고객이 이메일 크레딧을 선불로 구매하는 transactional email service입니다. 월간 플랜은 각 billing cycle마다 이메일 5,000개를 제공합니다. 잔액이 부족해진 고객은 다음 cycle을 기다리는 대신 top-up pack을 구매합니다. 이메일을 한 번 전송할 때마다 크레딧 1개가 차감됩니다.
이 튜토리얼에서는 이메일 provider로 Resend를 사용합니다. Resend의 free tier(월 3,000개 이메일)로 전체 flow를 구축하고 테스트할 수 있습니다. 이 billing pattern은 모든 provider에서 사용할 수 있습니다. resend.emails.send를 SendGrid, Postmark, Amazon SES 또는 자체 SMTP relay를 호출하는 코드로 바꾸면 됩니다.
완료하면 다음 방법을 알게 됩니다:
  • dashboard에서 이메일용 custom credit entitlement를 생성합니다.
  • subscription plan과 one-time top-up product에 크레딧을 연결합니다.
  • Resend를 통해 이메일을 전송하고 ledger entry와 함께 전송당 크레딧 1개를 차감합니다.
  • frontend에서 고객의 실시간 credit balance를 읽습니다.
  • Dodo Payments webhooks를 검증하고 credit.balance_low를 처리하여 잔액이 0이 되기 전에 고객에게 알립니다.

What We’re Building

MailKit은 두 가지 product를 판매합니다: 단위는 이메일 1개 = 크레딧 1개입니다. 고객은 token, batch 또는 가중 단위를 이해할 필요가 없습니다. 고객에게는 “이번 달 이메일 4,231개 남음”으로 표시됩니다. 시작하기 전에 다음이 필요합니다:
  • Dodo Payments account. 모든 작업은 test mode에서 수행합니다.
  • 무료 Resend account와 API key.
  • Node.js 22 이상 및 TypeScript에 대한 기본 지식.

Step 1: 이메일 Credit Entitlement 생성

credit entitlement는 MailKit이 판매하는 단위인 이메일 1회 전송을 정의합니다.
business의 credit entitlement를 표시하는 Products 아래의 Credits tab

The Credits tab under Products lists all your credit entitlements.

1

Open the Credits Section

  1. Dodo Payments dashboard에 로그인합니다.
  2. 사이드바에서 Products를 클릭합니다.
  3. Credits tab을 선택합니다.
  4. Create Credit을 클릭합니다.
2

Configure the Credit Unit

다음 값을 입력합니다:Credit Name: Email CreditsCredit Type: Custom UnitUnit Name: emailDefine Precision: 0. 이메일은 정수 단위이므로 잔액에 소수점이 필요하지 않습니다.Credit Expiry: 30 days. 사용하지 않은 크레딧은 발급 후 30일이 지나면 만료됩니다.
크레딧을 생성한 후에는 precision을 변경할 수 없습니다. 이메일, 메시지 또는 session처럼 개별 단위에는 0를 사용하세요.
3

Leave the Other Defaults

credit flow를 간단하게 유지하기 위해 이 튜토리얼에서는 rollover와 overage를 사용하지 않습니다. 나중에 credit 또는 각 product의 credit attachment에서 활성화할 수 있습니다.
4

Save and Copy the Credit ID

Create Credit을 클릭합니다. credit을 열고 cde_로 시작하는 ID를 복사합니다. backend는 balance 조회와 ledger entry에 이 ID를 사용합니다.
Email Credits entitlement가 준비되었습니다. 다음으로 고객에게 이를 부여하는 product를 생성합니다.

Step 2: Plan 및 Top-Up Pack 생성

동일한 Email Credits entitlement를 연결하는 두 product를 생성합니다. 하나는 각 billing cycle마다 이메일 5,000개를 제공하는 Subscription plan이고, 다른 하나는 필요할 때 이메일 5,000개를 추가하는 One Time top-up입니다.
이 튜토리얼에서는 usage meter 대신 ledger entry로 크레딧을 차감합니다. API call이 반환될 때 ledger debit이 적용되므로 meter 설정이 필요하지 않으며, 한 사용자 action이 정확히 크레딧 1개를 소비하는 경우에 적합합니다. token 또는 처리된 megabyte처럼 가중 단위에 적합한 ingested usage event에서 크레딧을 자동 차감하려면 Credit-Based Billing guide의 Usage Billing with Credits를 참조하세요.

MailKit Plan ($19/month, 이메일 5,000개)

1

Create the Subscription

  1. Products로 이동하고 Add Product를 클릭합니다.
  2. product details를 입력합니다:
Product Name: MailKit PlanDescription: 5,000 transactional emails per month.
  1. Pricing Type에서 Subscription을 선택합니다.
  2. recurring price를 설정합니다:
Price: 19.00Repeat payment every: 1 monthCurrency: USD
2

Attach the Email Credit Entitlement

Entitlements section에서 Credits 옆의 Attach를 클릭하고 다음과 같이 설정합니다:Select credits: Email CreditsCredits issued per billing cycle: 5000Low Balance Threshold (%): 20. 잔액이 cycle당 발급된 크레딧의 20%인 이메일 1,000개 미만으로 떨어지면 Dodo Payments가 credit.balance_low를 전송합니다.Import Default Credit Settings: 켭니다. 그러면 product가 Step 1의 30일 만료 설정을 사용합니다.크레딧을 product에 추가한 다음 product를 저장합니다. pdt_로 시작하는 product ID를 복사합니다.
Plan: $19/month이며 각 billing cycle마다 이메일 5,000개가 발급됩니다.

Top-Up Pack ($9 One-Time, 이메일 5,000개)

1

Create a One-Time Product

  1. Products로 이동하고 Add Product를 클릭합니다.
  2. product details를 입력합니다:
Product Name: Email Top-Up PackDescription: Add 5,000 emails to your MailKit balance.
  1. Pricing Type에서 One Time을 선택합니다.
  2. price를 설정합니다:
Price: 9.00Currency: USD
2

Attach the Credit Grant

Entitlements section에서 Credits 옆의 Attach를 클릭하고 다음과 같이 설정합니다:
  • Select credits: Email Credits
  • No of credits issued: 5000
one-time product는 고유한 만료 기간이 있는 크레딧을 부여합니다. Step 1에서 설정한 기본값에 따라 구매 후 30일입니다. Top-up credits는 subscription credits에 추가되며 이를 대체하지 않습니다.
product를 저장하고 ID를 복사합니다.
Top-Up Pack: 이메일 5,000개에 $9이며 payment가 성공하면 balance에 추가됩니다.

Step 3: Backend 설정

checkout을 생성하고, 이메일을 전송하고, balance를 읽고, webhook을 수신하는 Express server를 구축합니다.
1

Initialize the Project

다음과 같이 package.json에 dev script를 추가합니다:
tsx는 build step이나 tsconfig.json 없이 TypeScript를 직접 실행합니다. production에서는 tsconfig.json와 build script를 추가하세요.
2

Configure Environment Variables

Developer → API Keys에서 test mode API key를 가져오고 Step 1과 2의 ID를 사용하여 .env를 생성합니다:
.env
webhook endpoint를 생성한 후 Step 4에서 DODO_PAYMENTS_WEBHOOK_KEY를 입력합니다. resend.com/api-keys에서 Resend API key를 생성합니다.
첫 commit 전에 .env를 .gitignore에 추가합니다. API key를 절대 commit하지 마세요.
3

Build the Server

프로젝트 root에 server.ts를 생성합니다. server는 subscribe checkout, top-up checkout, balance read, send, webhook receiver의 다섯 route를 제공합니다.
webhook route는 raw request body를 수신해야 합니다. express.json()는 body를 parsed object로 바꾸지만, signature verification에는 Dodo Payments가 서명한 정확한 byte가 필요합니다. /webhooks/dodo route를 express.raw()와 함께 app.use(express.json()) line 위에 유지하세요.
backend가 준비되었습니다: subscribe, top-up, balance, send 및 webhook handler입니다.
4

Add a Demo UI

public/index.html를 생성합니다. 간단한 form에서 각 route를 호출하므로 browser에서 flow를 테스트할 수 있습니다:

Step 4: Webhook Endpoint 연결

credit.balance_low event를 사용하면 고객의 크레딧이 소진되기 전에 알릴 수 있습니다. 이 event가 없으면 고객은 이메일 전송이 실패한 뒤에야 문제를 알게 됩니다.
1

Expose Your Local Server

webhook에는 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. 자체 tunnel host를 사용하여 URL https://1234abcd.ngrok-free.app/webhooks/dodo를 입력합니다.
  3. credit.added, credit.balance_low, credit.rolled_over event를 선택합니다.
  4. Create endpoint를 클릭합니다.
  5. endpoint의 Overview tab에서 signing secret을 복사하여 .env의 DODO_PAYMENTS_WEBHOOK_KEY로 입력합니다.
  6. server를 재시작합니다.

Step 5: 전체 Flow 테스트

1

Start the Server

server가 MailKit running on http://localhost:3000를 log에 기록합니다. browser에서 해당 URL을 엽니다.
2

Subscribe a Test Customer

  1. section 1에서 test email address와 name을 입력한 다음 Get checkout link를 클릭합니다.
  2. link를 열고 test card로 checkout을 완료합니다.
  3. dashboard에서 Customers로 이동하고 cus_로 시작하는 새 customer ID를 복사합니다.
고객 balance에 이메일 5,000개가 있습니다. 확인하려면 Customers에서 고객을 열고 Credits tab을 선택합니다.
3

Send an Email

  1. section 3에 customer ID를 붙여 넣습니다.
  2. To를 모든 message를 수신하는 Resend test address인 delivered@resend.dev로 둡니다.
  3. Send를 클릭합니다.
page에 Resend message ID가 표시됩니다. section 2에서 balance를 새로 고칩니다. 4,999로 표시됩니다. API call이 반환되는 즉시 ledger debit이 balance에 반영됩니다.
4

Trigger the Low-Balance Webhook

threshold는 20%, 즉 cycle당 발급되는 이메일 5,000개의 1,000개입니다. 이메일 4,000개를 전송하지 않고 threshold에 도달하려면 dashboard에서 balance를 수동으로 차감합니다:
  1. Customers에서 고객을 열고 Credits tab을 선택한 다음 Email Credits를 선택합니다.
  2. Apply Credit/Debit을 클릭하고 Debit을 선택한 뒤 4000를 입력합니다. 이제 balance는 정확히 1,000이며 아직 threshold 미만은 아닙니다.
  3. demo에서 이메일을 하나 더 전송합니다. balance가 999로 떨어집니다.
webhook이 도착하면 server에 다음이 기록됩니다:
server가 webhook을 수신하고 검증했습니다. production에서는 이 지점에서 고객에게 이메일을 보내거나 in-app banner를 표시합니다.
5

Buy a Top-Up Pack

  1. section 4에 customer ID를 붙여 넣습니다.
  2. Buy 5,000 emails를 클릭하고 test checkout을 완료합니다.
  3. balance를 새로 고칩니다. 5,000 증가합니다.
Dodo Payments가 transaction_type: "credit_added"와 함께 credit.added event를 전송합니다. 이 event에 연결된 grant에는 source_type: one_time가 있으며 List Customer Grants API로 이를 조회할 수 있습니다. Top-up credits는 subscription credits에 추가됩니다. debit은 먼저 만료되는 grant에서 차감되며, 두 grant가 동시에 만료되면 더 오래된 grant에서 차감됩니다.
6

Test the Hard Stop

dashboard에서 balance를 0으로 차감한 다음 이메일을 하나 더 전송해 봅니다. server가 402와 함께 응답합니다:
해당 402는 application의 enforcement입니다. Dodo Payments balance API를 source of truth로 사용하고 client에 balance를 cache하지 마세요.

문제 해결

signature는 raw HTTP body를 포함합니다. express.json()는 body를 parsed object로 바꾸므로 verification이 실패합니다. /webhooks/dodo를 express.raw({ type: 'application/json' })와 함께 app.use(express.json()) line 위에 등록합니다. 그런 다음 DODO_PAYMENTS_WEBHOOK_KEY가 endpoint의 Overview tab에 있는 signing secret과 일치하는지 확인합니다.
다음 세 가지를 순서대로 확인합니다:
  1. 고객이 checkout을 완료했는지 확인합니다. 크레딧은 checkout session이 생성될 때가 아니라 payment가 성공할 때 발급됩니다.
  2. .env의 CREDIT_ENTITLEMENT_ID가 product에 연결된 credit과 일치하는지 확인합니다. balance 및 ledger call은 이 ID를 사용하므로 불일치하면 다른 credit을 조회하거나 차감합니다.
  3. 전달하는 customer_id가 자체 database의 ID가 아니라 Dodo Payments customer ID인지 확인합니다. 이 ID는 cus_로 시작합니다.
test sender onboarding@resend.dev는 Resend account의 email address 또는 delivered@resend.dev로만 전송합니다. 다른 사람에게 보내려면 domain을 verify하고 해당 domain의 from address를 사용합니다.

구축한 항목

One Reusable Credit Unit

한 번 정의하고 subscription plan과 top-up pack 양쪽에 연결한 Email Credits입니다.

Subscription with Prepaid Allowance

$19/month로 각 billing cycle마다 이메일 5,000개를 제공합니다. 고객은 무엇에 비용을 지불하는지 알고, 운영자는 최대 비용을 파악할 수 있습니다.

Top-Up Pack

subscription credits에 이메일 5,000개를 추가로 부여하는 one-time product이며 plan 변경이 필요하지 않습니다.

Direct Ledger Debits

각 전송 후 createLedgerEntry call을 한 번 수행하며, meter나 aggregation delay가 필요하지 않습니다. Resend message ID를 idempotency key로 사용하면 동일한 전송에 대한 두 번째 debit을 방지할 수 있습니다.

Credit-Based Billing Reference

Rollover, overage modes, ledger management 및 전체 credit API입니다.
도움이 필요하면 Discord Community에서 질문하거나 support@dodopayments.com으로 이메일을 보내세요.
마지막 수정일 2026년 9월 26일