Context

A membership site on WordPress used Stripe for renewals. Webhooks updated access in theory. In practice, hosting restarts and plugin updates dropped events. Support tickets: "I paid but my account is locked."

They wanted insurance-not a rewrite of the whole membership stack.

What I built

  • Verified Stripe webhook handler with signature check and idempotency keys stored in DB
  • Nightly reconciler: pull last 48h of Stripe charges, compare to local membership table, flag gaps
  • Slack message on mismatch with customer email, charge ID, and suggested fix link
  • Small admin action: "replay webhook" for a single event without touching unrelated rows

Technical approach

Event log table as source of truth for processed webhook IDs. Reconciler read-only on Stripe side; fixes applied through the same code path as live webhooks to avoid two divergent update mechanisms.

Staging tested with Stripe CLI fixture events before production deploy.

Outcomes

  • Missed renewal incidents dropped to near zero after first month
  • Support could resolve most mismatches from Slack link without developer access
  • Plugin upgrades continued; reconciliation caught the one bad deploy before Monday traffic

Stack

Stripe API · WordPress · PHP/Node glue · PostgreSQL · Slack incoming webhook