koala73 / koala73/worldmonitor
epic: usage-based overage billing on Dodo (Phase 2 of #3199)
- Dominant language
- TypeScript
- Stars
- 86.6k
- Forks
- 13.1k
- Avg merge
- 8h 4m
- Merged PRs (30d)
- 825
Description
Blocked by #3199 (Phase 1 ships the per-account usage meter). This epic bills the meter as **overage** so customers crossing their included allowance pay per-use, rather than being hard-rejected.
## Why this is a separate phase
#3199 conflated two limits with opposite correct behaviors. Phase 1 fixes the infra half (per-minute burst = hard 429) and **meters** the commercial allowance without rejecting it. This epic adds the billing half: the metered allowance becomes a Dodo free threshold with priced overage.
## Confirmed architecture
- Define a Dodo meter `api.request` (Count aggregation); the included allowance (`apiDailyAllowance`) becomes Dodo's **free threshold**, overage at a per-unit price.
- **Async batched** `POST /events/ingest` from the Phase-1 meter buffer (cron or `waitUntil`), idempotent `event_id`, **never on the request hot path**; resolve `customer_id` via the existing `dodoCustomerId ↔ userId` map (`convex/payments/subscriptionHelpers.ts:422`, `by_dodoCustomerId` index).
- Catalog gains overage price + cycle fields; subscribe Dodo `credit.balance_low` webhooks → 80%/100% notification emails (reuse `convex/payments/subscriptionEmails.ts`); customer-configurable spend cap (Phase-1's 10× ceiling is its backstop).
- Provider supports this natively: [usage-based billing](https://docs.dodopayments.com/features/usage-based-billing), [credit-based billing](https://docs.dodopayments.com/features/credit-based-billing).
## Open decisions (resolve first — these gate the child tasks)
- [ ] **Model**: usage-based ($/unit billed in arrears) vs credit-based (prepaid packs). Phase-1 meter is forward-compatible with either.
- [ ] **Pricing**: overage $/unit, and whether the included allowance is billed **daily or monthly** (billing cycles are monthly).
- [ ] **5xx exclusion** from the billable meter — Phase 1 counts 5xx (no refund); billing likely needs to exclude them (see #3199 plan OQ4).
## Reference
Phase-1 plan + grounding: `docs/plans/2026-06-30-001-feat-per-tier-api-rate-limits-plan.md` (see "Deferred to Follow-Up Work").
Contributor guide
Research direction
Start with the Phase-1 plan at docs/plans/2026-06-30-001-feat-per-tier-api-rate-limits-plan.md, especially its deferred follow-up work and OQ4. Review the customer mapping in convex/payments/subscriptionHelpers.ts:422 and notification reuse in convex/payments/subscriptionEmails.ts. This epic is ready for implementation only after the usage-versus-credit model, pricing and billing cycle, and 5xx metering decisions are resolved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, payments
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100