fix(billing-blocked): block platform usage if payment fails for regular subs as well#1541
Merged
icecrasher321 merged 1 commit intostagingfrom Oct 3, 2025
Merged
Conversation
Contributor
There was a problem hiding this comment.
Greptile Overview
Summary
This PR fixes a billing enforcement gap by extending invoice payment failure handling to include regular subscription renewals. Previously, the webhook handler in `apps/sim/lib/billing/webhooks/invoices.ts` only processed overage billing invoice failures, allowing users to continue using the platform when their base subscription payments failed.The change modifies the invoice payment failure logic to handle both invoice types by:
- Removing the early return: The original code had an early return for non-overage invoices (
invoice.metadata?.type !== 'overage_billing'), which prevented processing of regular subscription failures - Adding invoice type detection: New logic differentiates between overage and regular subscription invoices
- Implementing flexible subscription ID extraction: Overage invoices store the subscription ID in metadata, while regular subscription invoices store it in
parent.subscription_details - Applying consistent blocking logic: The same user blocking mechanism (blocking after attemptCount >= 1) now applies to all invoice payment failures
This ensures that users are blocked from platform usage when any payment fails, whether it's a base subscription renewal or an overage charge, maintaining consistent billing enforcement across the application's subscription model.
Changed Files
| Filename | Score | Overview |
|---|---|---|
| apps/sim/lib/billing/webhooks/invoices.ts | 4/5 | Extended invoice payment failure handling to process both regular subscription and overage billing invoice failures, ensuring consistent platform usage blocking |
Confidence score: 4/5
- This PR addresses a clear billing enforcement gap with focused changes that improve system consistency
- Score reflects solid logic with proper type handling, though the manual testing approach and webhook complexity warrant careful review
- Pay close attention to the subscription ID extraction logic for different invoice types and ensure Stripe webhook testing covers both scenarios
Sequence Diagram
sequenceDiagram
participant Stripe
participant WebhookHandler as "Invoice Webhook Handler"
participant DB as "Database"
participant Logger
Note over Stripe,Logger: Invoice Payment Failed Flow
Stripe->>WebhookHandler: "invoice.payment_failed event"
WebhookHandler->>Logger: "Log payment failure details"
alt Overage Invoice
WebhookHandler->>WebhookHandler: "Extract subscription ID from metadata"
else Regular Subscription Invoice
WebhookHandler->>WebhookHandler: "Extract subscription ID from parent.subscription_details"
end
alt No subscription ID found
WebhookHandler->>Logger: "Log: No subscription found, skipping"
WebhookHandler-->>Stripe: "Return early"
end
WebhookHandler->>Logger: "Warn: Invoice payment failed with details"
alt Attempt count >= 1
WebhookHandler->>Logger: "Error: Payment failure - blocking users"
WebhookHandler->>DB: "SELECT subscription by stripeSubscriptionId"
alt Team/Enterprise Plan
WebhookHandler->>DB: "SELECT members by organizationId"
loop For each member
WebhookHandler->>DB: "UPDATE userStats SET billingBlocked = true"
end
WebhookHandler->>Logger: "Info: Blocked team/enterprise members"
else Individual Plan
WebhookHandler->>DB: "UPDATE userStats SET billingBlocked = true"
WebhookHandler->>Logger: "Info: Blocked user"
end
alt Subscription not found
WebhookHandler->>Logger: "Warn: Subscription not found in database"
end
end
Note over Stripe,Logger: Invoice Payment Succeeded Flow
Stripe->>WebhookHandler: "invoice.payment_succeeded event"
WebhookHandler->>DB: "SELECT subscription by stripeSubscriptionId"
alt No subscription found
WebhookHandler-->>Stripe: "Return early"
end
alt Team/Enterprise Plan
WebhookHandler->>DB: "SELECT members by organizationId"
loop Check if any member was blocked
WebhookHandler->>DB: "SELECT billingBlocked from userStats"
end
loop For each member
WebhookHandler->>DB: "UPDATE userStats SET billingBlocked = false"
end
else Individual Plan
WebhookHandler->>DB: "SELECT billingBlocked from userStats"
WebhookHandler->>DB: "UPDATE userStats SET billingBlocked = false"
end
alt Was previously blocked
WebhookHandler->>WebhookHandler: "resetUsageForSubscription()"
alt Team/Enterprise Plan
WebhookHandler->>DB: "SELECT members by organizationId"
loop For each member
WebhookHandler->>DB: "UPDATE userStats reset usage counters"
end
else Pro Plan
WebhookHandler->>DB: "UPDATE userStats reset usage counters with snapshot"
end
end
1 file reviewed, no comments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Regular subscription payment failures were not being handled. This fixes that.
Type of Change
Testing
Tested manually.
Checklist