While working around paid Telegram communities, I keep coming back to one deceptively simple problem:
Stopping a subscription from renewing is not the same thing as removing access right now.
The naive flow looks easy:
payment succeeds → let the user in
payment fails → remove the user
Then recurring billing gets involved.
Say someone pays for access from September 1 to September 30 and turns off renewal on September 10. They shouldn't be charged again in October. But they've still paid for another 20 days of access.
So a “canceled” flag alone isn't enough to decide whether that person should still be inside the community.
And that's before the less clean cases show up:
I've started thinking about this as three separate pieces of state:
Payment: Did the current payment actually succeed?
Subscription: Is it active, past due, scheduled to end, or already ended?
Access: Should this user have access right now?
That last one is really an entitlement. It can be derived from billing, but it isn't necessarily the same thing as billing state.
This came up while working on Nemiling, which handles monetization and access automation for Telegram communities.
The payment itself is usually the straightforward part. Keeping billing events and actual Telegram membership in sync is where the interesting edge cases start showing up.
For a small community, handling some of this manually is probably fine. Once subscriptions start scaling, though, you need clear access rules and event handling that doesn't break when the same event arrives twice or in the wrong order.
Curious how other founders handle this. Do you derive access directly from your billing provider, or keep a separate entitlement/access layer in your app?
This is exactly the distinction I’ve found useful too — billing state and access state shouldn’t really be the same thing. Once you have retries, duplicate/out-of-order events and cancellations at period end, a simple subscription_status field gets messy fast.
I’d keep an explicit entitlement/access layer and make webhook processing idempotent. That makes the “should this user have access right now?” decision much easier to reason about.