The valley of webhooks

The third time I’ve built the same system three times now, at three different companies, for three different providers. It never has a name and it never appears on a roadmap, but it always goes the same way: the truth about your own customers lives in someone else’s database. The users live in an identity provider, the subscriptions in Stripe, the bounces in whatever sends your email, and your product needs that truth locally. So you subscribe to webhooks and keep a copy. The first time, I thought I was building an endpoint: one route that parses the JSON and updates a row, an afternoon of work. The afternoon grew into a week. First came signature verification, because an open endpoint that mutates your database is a hole. Then the dedup table, because deliveries arrive twice and the docs cheerfully call this “at-least-once.” Then the handler got a buffer, because a membership.created sometimes shows up before the user.created it points to. Then the bootstrap importer, because webhooks only tell you what happens after you subscribe, and it raced the live events, so it grew a locking scheme. And finally came the reconciliation cron: a job that crawls the provider’s list APIs at 3 a.m., diffs them against our tables, and quietly fixes what disagrees. I want to be honest about what that cron is. It’s a written confession. It says: I do not trust the copy I built, and I have no way to know when it’s wrong, so I will re-derive it from scratch every night, forever. The trust was gone for a reason. The drift never announces itself; ours was found by a support ticket. A customer had cancelled months earlier and our database still said active; some customer.subscription.deleted had evaporated between Stripe and us, and nothing anywhere was capable of noticing: not their…

Half-Baked Product

The Founder A freshly minted founder decides to get into the oven business. He can’t bake a cake or knead bread, but he knows the kitchen appliance market inside and out. He’s analyzed every business in Spain and reached a conclusion: if he sells a new oven to the country’s pizza makers, pastry chefs, and bakers, he only needs to capture 10% of the market to become a billionaire. 10% always looks small when you type it into an Excel spreadsheet. The founder is very good. He builds a plan that, on paper, is flawless and airtight: manufacture a more efficient oven using new technology. Selling it is easy. Want to work more efficiently? Buy our oven. End of pitch. The founder has experience talking to investors and raises enough money to build an MVP. The Engineer The founder looks for someone who knows how to build ovens and finds an engineer from a prestigious school. The engineer has spent 10 years building ovens and knows how to make one. More than that: he’s the kind of person who spends all day talking and arguing about ovens. He goes to oven conferences. When he gets home at night, he argues for hours on Italian forums about which type of oven is best. The Italian forums are, to him, the ultimate source of oven-truth. He’s tired of building ovens at Corporate Oven. Ten years making the same oven he’s told to make. He wants the freedom to build his own. The founder offers him 20% of the company and total freedom to build the perfect oven. The salary isn’t great, but there’s the promise: if things go well, someday he could be a millionaire. And something more important than money: he’ll finally get to build the oven of his dreams. He signs. The MVP With little money and lots of enthusiasm, they build an MVP. Two months later it’s done. It’s a functional oven and,…