Skip to content

Improve webhook handler robustness: upserts, final state, customer.deleted#29

Open
advaitpaliwal wants to merge 1 commit intoget-convex:masterfrom
advaitpaliwal:fix/webhook-handler-robustness
Open

Improve webhook handler robustness: upserts, final state, customer.deleted#29
advaitpaliwal wants to merge 1 commit intoget-convex:masterfrom
advaitpaliwal:fix/webhook-handler-robustness

Conversation

@advaitpaliwal
Copy link
Contributor

Summary

Five webhook handler fixes in one PR since they're all closely related:

  • handleSubscriptionUpdated now upserts — if subscription.updated arrives before subscription.created (webhook ordering), the data was silently dropped. Now creates the record if missing, preventing lost subscriptions.
  • handleInvoiceCreated now updates existing invoicesinvoice.finalized called the same handler as invoice.created, but it was insert-only. Updated amounts, status, and subscription links from finalization were silently dropped. Now patches existing records.
  • handleSubscriptionDeleted stores final state — previously only set status: "canceled" and discarded currentPeriodEnd, cancelAt from the event. Now stores the final timestamps.
  • Add customer.deleted event handling — deletes the customer record when a customer is removed in Stripe (dashboard or API). Previously left stale records.
  • Fix cancelAt || undefinedcancelAt ?? undefined|| coerces a valid 0 timestamp to undefined. Changed to ?? throughout for correctness.

Test plan

  • Verify subscription.updated arriving before subscription.created now creates the subscription record
  • Verify invoice.finalized updates existing invoice records (amount, status)
  • Verify subscription.deleted stores currentPeriodEnd and cancelAt in the record
  • Verify customer.deleted removes the customer from the database
  • Verify existing webhook flows still work unchanged

🤖 Generated with Claude Code

- handleSubscriptionUpdated now upserts: creates the subscription if
  it doesn't exist yet (fixes webhook ordering where updated arrives
  before created). Requires stripeCustomerId passed from the event.

- handleInvoiceCreated now updates existing invoices, fixing
  invoice.finalized events silently dropping updated amounts/status
  when the invoice was already created by invoice.created.

- handleSubscriptionDeleted now stores final state (currentPeriodEnd,
  cancelAt) instead of only setting status to "canceled" and
  discarding all other fields from the event.

- Add customer.deleted webhook event handling that removes the
  customer record from the database.

- Fix cancelAt || undefined → cancelAt ?? undefined throughout
  to avoid coercing a valid 0 timestamp to undefined.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant