Repository navigation
0.1.8: Stop reusing deleted or other users' Stripe customers - #79
Open
michaelshimeles wants to merge 1 commit into
Open
michaelshimeles wants to merge 1 commit into
michaelshimeles wants to merge 1 commit into
Conversation
- Customers deleted in Stripe are marked deleted. getOrCreateCustomer, getCustomerByUserId, and getCustomerByEmail skip them, so a user whose customer was deleted gets a new one instead of a "No such customer" checkout error. - getOrCreateCustomer only reuses an email match when that customer has no userId, then links it to the user in Stripe and Convex. Before, any user sharing an email could be handed another user's customer and its billing portal. - customer.updated creates missing customers, links userId from metadata, and leaves deleted customers alone. - User and email lookups return the newest customer, and getSubscriptionByOrgId prefers a live subscription over old canceled ones. Co-authored-by: Cursor <cursoragent@cursor.com>
commit: |
michaelshimeles
marked this pull request as ready for review
November 3, 2026 22:01
This branch has not been deployed
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.
Second of five stacked PRs, part of the 0.1.8 patch. Based on the webhook correctness PR.
What changed
getOrCreateCustomercould hand one user another user's Stripe customer. When nothing matched theuserId, it fell back to any customer with the same email, so a second account with that email got the first account's customer, and its Customer Portal link showed the first user's cards and invoices. It now only reuses an email match when that customer has nouserId, and then links it to the user in Stripe and in Convex.deleted: trueinstead of only having their PII scrubbed.getOrCreateCustomer,getCustomerByUserId, andgetCustomerByEmailskip them, so a user whose customer was deleted gets a new one instead of a "No such customer" error at checkout. The subscription and payment fallbacks also skip deleted customers.getCustomerByUserIdandgetCustomerByEmailreturn the newest match instead of the oldest.customer.updatedcreates the customer when it isn't stored yet and linksuserIdfrom metadata. Customers created before the webhook was set up never synced before. It also leaves deleted customers alone, so a late update can't restore their details.getSubscriptionByOrgIdused.first(), which returned the oldest subscription, often a canceled one after the org resubscribed. It now prefers active or trialing, then past due, unpaid, or paused, then incomplete, with ties going to the newest.deletedis a new optional field on customer documents. Apps with hand-writtenreturnsvalidators for customer data will need to add it. The next PR exports validators so that doesn't keep happening.One gap I left alone:
createCustomerstill usescreate_customer_${userId}as the idempotency key. If a customer is deleted within 24 hours of being created, Stripe replays the deleted customer for that key.Testing
npm run build,npm test(63 passing),npm run typecheck,npm run lint.customer.updatedcreating and linking customers, late updates after deletion, and the org subscription preference. Client tests for skipping a deleted linked customer, refusing another user's email match, and claiming an unclaimed one.