Dev.to · 6 min read

Building an open source subscription backend

Building an open source subscription backend

My first attempt to add subscriptions to my app failed, so I built SubTru. SubTru is an open source, self-hostable API that processes subscription events from Stripe, the Apple App Store, and Google Play. Your app can then call SubTru's GET /access endpoint to fetch any user's subscription status. Below, I discuss some of the challenges I faced and the design decisions I made along the way. It started with disaster I had no idea how challenging adding subscriptions to an app could be. My first attempt at this was a disaster. I had spent months writing the code to handle my users' subscriptions, but all it took was one small misconfiguration for things to break. Long story short, my logic didn't update my customer's subscription status after they made a purchase. I was able to quickly fix the problem, but I felt horrible that I had failed my customer. I felt so bad about the situation, that I vowed to build the most bulletproof subscription handling infrastructure possible and make it open source, so this wouldn't have to happen to anyone else. What is subscription handling? Subscription handling is complicated. Providers like Stripe, the Apple App Store and Google Play send out events (webhooks or real-time developer notifications in Google's case) whenever your users purchase or change their subscriptions. Those events need to be processed to create and maintain an accurate record of your users' subscriptions. It sounds simple enough on the surface, but here are a few challenges I faced: Providers often send multiple events for a single subscription change. Events sometimes arrive out of order or late. Provider events need to be verified before they are trusted. Each provider sends a different payload structure and has different verification mechanisms, so the complexity is multiplied by each provider you're using. Building a subscription service Design requirements There were four main requirements I had in mind for the subscription handling infrastructure I wanted to build. I wanted something that could: Receive subscription events from Stripe, the Apple App Store, and Google Play Process those events and write to a database (to maintain subscription records) Make my users' subscription info available to my app for product access decisions Be easily self-hostable so it could be used by other developers These requirements helped me narrow down the possible designs for the infrastructure, but even still, I could have built things in a variety of ways without any of them being "wrong". With most system design problems, they are nuanced and come down to the advantages and tradeoffs unique to your situation. Design decisions Architecture Since this service would need to receive subscription events from providers and also make user subscription data available to external apps, it made sense to design part of it as an API. I added an HTTP POST /webhooks endpoint for each provider to send events to, and a GET /access endpoint for apps to fetch user subscription access data. This service would also need to process those provider events and store user subscription data somewhere. Trying to pick the "right" design for event processing was challenging because there were so many ways to combine or split functionality between different services. After weighing the pros and cons around things like failure isolation, failure recovery, scalability, and deployment simplicity, I decided to use a single service to receive and process events. I've considered adding a queue for incoming events so they can be processed separately from when they are received, but there isn't a clear need for that at the moment since the system isn't bottlenecked, and providers can resend events that failed to process. The current approach also has much less complexity for deployment and maintainability. Database The database decision wasn't as crucial. Since the service just needs a place to store and read data, both a relational or NoSQL DB could have been used here. I decided to go with Postgres since a lot of the data we store is relational in nature, and Postgres is widely adopted by the open source community. Deployment I try to use serverless functions when they make sense, because I like that they eliminate idle compute costs, but they also have some drawbacks like cold starts, setup complexity, and less support outside AWS, Azure, or Google Cloud. For those reasons, and given our requirements, I figured a containerized service on a long-lived machine made more sense. I added a Dockerfile in the GitHub repo so self-hosters can easily deploy the Docker image to their hosting platform of choice. It also doesn't stop self-hosters from deploying to serverless container platforms if they prefer. I've also provided SQL migration scripts in the repo so self-hosters can quickly set up their Postgres database. Adding subscriptions to an app Now, whenever I need to add subscription handling to an app, I don't have to spend months rewriting everything from scratch. All I have to do is deploy the service from the Docker image, run the migration scripts to set up the database, and configure my subscription providers (Stripe, the Apple App Store, and/or Google Play) to send events to the API. Once that's done, I can call the GET /access endpoint from my app whenever I need to fetch a user's subscription status. Here's an example GET /access response: { "entitlements": [ { "productId": "pro_subscription", "hasAccess": true, "accessReason": "active_subscription", "accessEndsAt": "2026-12-25T12:43:36.111+00:00" } ] } My app then uses the productId and hasAccess values to decide what features my user has access to. I can optionally cache the customer's subscription status for a duration so I don't have to make repeated calls to the API. Learn more This project is called SubTru. Here's a link to the homepage if you want to learn more. SubTru is completely open source under the Apache 2.0 license, and all contributions are greatly appreciated. There is also a managed, SubTru Cloud offering with a dashboard if you would rather not self-host. Thank you so much for your time. I know it's valuable, so I don't take it for granted. Let me know what you think about SubTru so I can learn what's going right and what could be better! Please consider giving SubTru a star on GitHub. It would mean the world to me.

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News