Nico here. I’m building Keylight ( https://keylight.dev ), so I want to mention that up front. This isn't really a "look what I built" post. The interesting part is the architectural decision behind it. I got tired of app licensing being tied to whatever payment provider you start with. At first, it feels fine. Stripe, Paddle, Lemon Squeezy, Polar, Gumroad, and others offer some version of “customer paid” and maybe license keys. But the app doesn't care about most of that. What the app cares about are boring runtime questions: Can this device run the app? Is this license still valid? Is the user in trial, paid, expired, free, or grace? Can the app keep working offline? Did this user wipe their Mac and reinstall? Can I rotate signing keys without breaking old builds? That is a different problem from payments. So the thing I’m building treats payments as inputs, not as the licensing system itself. Provider webhooks come in, get normalised, and create an internal license state. The app only reads that state through the SDK. In my case, it is a signed LicenseState with device activation, offline leases, encrypted local storage, trial/free/paid states, and grace rules. The annoying parts are where it gets interesting: * Webhook retries and out-of-order events * Refunds, failed renewals, and chargebacks * Offline access without trusting local files too much * Device limits without punishing normal reinstall cases * Migrating old customers from another provider * Not making the app care whether the user paid through Stripe, Paddle, or something else The tradeoff is that this adds one more layer. You have to own the license state machine instead of just accepting what the payment provider gives you. The upside is that your app uses one licensing protocol, and your payment stack can change behind it. That is what matters most to me: avoiding the "we need to migrate licensing again" problem later. submitted by /u/nicolas1410 [link] [comments]