Sure thing! Basically I set out to use Stripe's built-in tools as much as possible, rather than duplicating the state on our side - storing partial data in your own DB is one of the biggest pain points of subscription systems in my experience. So for this app it didn't have a DB at all - Stripe was the source of truth.
The way it worked was fairly straightforward: a user would click a link from their account area and it would include their Stripe customer ID in the request (all our users had already had accounts created due to our main booking system). The app then span up a new GenServer to represent that customer, which would pull down all the data it needed from Stripe's API as soon as it initialised. There was also some generic data stored in a "global" GenServer to cover stuff like plans etc (I can't remember how I had that refreshing, probably via webhooks).
Then as the user went through the subscription process or management process, any changes they made would be made through calls to their own personal GenServer, which on write would first write to the Stripe API, then update its own cache with the new state returned from Stripe to ensure consistency. These GenServers were kept alive by a timer set on interactions with it, and would automatically shut down 30 minutes after the user stopped interacting with it, discarding all the data it held. Then when they next return, it fetches the state from Stripe again. It also listened for webhooks and would update running GenServer instances with data it received to ensure they were consistent, and just ignored any for users that weren't currently running.
Overall I was really happy with it - it was really performant due to the data caching but also didn't suffer from staleness issues :)