-
Notifications
You must be signed in to change notification settings - Fork 3.3k
feat(billing): bill by threshold to prevent cancellation edge case #1583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Summary
This PR implements a threshold-based billing system to prevent revenue loss from payment method removal edge cases. The core change introduces automatic invoice generation and charging whenever a user accumulates more than $50 in unbilled overages, rather than waiting until the end of the billing period. This caps the maximum potential loss at $50 per user.The implementation adds a new billedOverageThisPeriod field to the userStats database schema to track how much overage has already been billed within the current period. This prevents double-billing when the regular end-of-period invoice is generated. The system integrates with existing Stripe billing workflows and supports both individual Pro plans and Team plans with pooled usage.
Key components include: a new threshold-billing.ts module with functions for individual users (checkAndBillOverageThreshold) and organizations (checkAndBillOrganizationOverageThreshold), integration points in cost update APIs (/api/billing/update-cost and /api/wand-generate), and modifications to existing billing webhooks to account for previously billed amounts. The system uses database transactions with row-level locking to ensure consistency and includes comprehensive error handling.
The billing logic spreads large overage charges throughout the month instead of accumulating them into potentially large end-of-period bills, improving cash flow and reducing payment failure risk. Documentation has been updated to explain the new billing model to users, setting proper expectations about when charges will occur.
Important Files Changed
Changed Files
| Filename | Score | Overview |
|---|---|---|
| apps/sim/lib/billing/threshold-billing.ts | 4/5 | Implements core threshold billing logic with automatic invoice creation when overages exceed $50 |
| packages/db/schema.ts | 5/5 | Adds billedOverageThisPeriod field to track already-billed overage amounts |
| packages/db/migrations/0097_dazzling_mephisto.sql | 5/5 | Database migration to add the new billing tracking column |
| apps/sim/app/api/billing/update-cost/route.ts | 4/5 | Integrates threshold billing checks into cost update API endpoint |
| apps/sim/lib/billing/webhooks/invoices.ts | 4/5 | Updates invoice handling to prevent double-billing by accounting for threshold-billed amounts |
| apps/sim/lib/billing/webhooks/subscription.ts | 4/5 | Modifies subscription cancellation to only bill remaining unbilled overage |
| apps/sim/app/api/wand-generate/route.ts | 4/5 | Adds threshold billing integration to wand generation workflow |
| apps/docs/content/docs/en/execution/costs.mdx | 5/5 | Documents the new threshold billing model for user transparency |
| apps/sim/lib/env.ts | 5/5 | Adds configurable threshold amount environment variable |
| apps/sim/lib/billing/constants.ts | 5/5 | Defines default $50 threshold constant |
| packages/db/migrations/meta/_journal.json | 5/5 | Migration journal entry for database schema change |
| packages/db/migrations/meta/0097_snapshot.json | 5/5 | Complete schema snapshot after threshold billing migration |
Confidence score: 4/5
- This PR addresses a legitimate business risk with a well-architected solution that limits financial exposure to $50
- Score reflects complex billing logic changes that require careful testing, especially around edge cases and double-billing prevention
- Pay close attention to threshold-billing.ts, invoice webhooks, and subscription cancellation logic for potential race conditions or billing inconsistencies
Sequence Diagram
sequenceDiagram
participant User
participant ExecutionLogger
participant ThresholdBilling
participant Database
participant Stripe
participant WebhookHandler
User->>ExecutionLogger: "Execute workflow"
ExecutionLogger->>Database: "Update user stats with execution cost"
ExecutionLogger->>ThresholdBilling: "checkAndBillOverageThreshold(userId)"
ThresholdBilling->>Database: "Get user subscription and usage stats"
ThresholdBilling->>ThresholdBilling: "Calculate unbilled overage"
alt Unbilled overage >= $50 threshold
ThresholdBilling->>Database: "Lock user stats for update"
ThresholdBilling->>Stripe: "Create overage invoice"
ThresholdBilling->>Stripe: "Add invoice item for overage amount"
ThresholdBilling->>Stripe: "Finalize and attempt payment"
ThresholdBilling->>Database: "Update billedOverageThisPeriod"
end
Note over User,WebhookHandler: End-of-period billing
WebhookHandler->>Database: "Calculate total and billed overage"
WebhookHandler->>ThresholdBilling: "getBilledOverageForSubscription()"
alt Remaining unbilled overage > 0
WebhookHandler->>Stripe: "Create final period overage invoice"
WebhookHandler->>Database: "Reset usage stats for new period"
else No remaining overage
WebhookHandler->>Database: "Reset usage stats for new period"
end
Note over User,WebhookHandler: Payment failure scenarios
alt Invoice payment fails
WebhookHandler->>Database: "Block users after first failure"
else Invoice payment succeeds
WebhookHandler->>Database: "Unblock users if previously blocked"
end
12 files reviewed, 6 comments
…1583) * feat(billing): bill by threshold to prevent cancellation edge case * fix org billing * fix idempotency key issue * small optimization for team checks * remove console log * remove unused type * fix error handling
Summary
Generate and charge an invoice everytime >50 dollars in overages is recorded. That way the max loss that can be taken is 50 -- in case payment method is removed and manual invoice remains unpaid.
Type of Change
Testing
IN PROGRESS
Checklist