Auto-Removal Without the Drama: Grace Periods and the Ban API Footguns
Auto-Removal Without the Drama: Grace Periods and the Ban API Footguns
Removing lapsed members is the least glamorous part of running a paid channel and the easiest to get badly wrong. Two things go wrong: the policy, and the API.
The API problems are worse, because they are silent.
Footgun one: unbanning removes people
From Telegram's Bot API documentation for unbanChatMember:
"By default, this method guarantees that after the call the user is not a member of the chat, but will be able to join it. So if the user is a member of the chat they will also be removed from the chat."
Read that again. Calling unbanChatMember on somebody who is currently a member kicks them out.
The name suggests a safe, corrective action. It is not. The method guarantees a post-condition — "not a member, but able to join" — and it will remove an active member to get there.
The realistic disaster: a member lapses, gets removed, resubscribes, rejoins. Later, a cleanup job runs unbanChatMember across everyone who was ever removed, intending to tidy up ban state. It ejects your paying subscriber without a word.
The fix is one parameter:
unbanChatMember(chat_id, user_id, only_if_banned=True)
only_if_banned does nothing if the user isn't banned. Use it every single time unless you have thought hard about why you shouldn't. There is no good reason to omit it in a membership system.
Footgun two: short bans are permanent
From the documentation for banChatMember:
"If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever."
Both ends of that range are traps, and the lower one is vicious.
A natural implementation of "remove this person but let them rejoin when they pay" is a very short ban followed by an unban. If your until_date computes to less than 30 seconds from now — a rounding error, a clock skew, an off-by-one — the user is banned forever. No error is returned. It looks like it worked.
Same at the other end: a ban intended as "one year" that computes to 366 days plus a second is permanent.
Safe patterns:
- To remove someone who should be able to return:
banChatMemberthenunbanChatMember(only_if_banned=True). Explicit and predictable. - If you must use
until_date, keep it comfortably inside the window — at least a few minutes, well under 366 days — and never compute it from a value that could round to zero.
Footgun three: revoking the primary link
From revokeChatInviteLink:
"If the primary link is revoked, a new link is automatically generated."
Helpful, and a problem if you didn't expect it. Revoking the primary link invalidates every published copy of it — your website, your pinned posts, your ads, the link in a subscriber's saved messages — and silently issues a replacement.
Revoke non-primary links you created for a purpose. Leave the primary link alone unless you specifically intend to invalidate everything.
Now the policy
With the API hazards handled, the question is when to remove someone.
Removing at the instant of failure is the wrong default. A large share of failed renewals are people who wanted to stay and were short on Stars — a prepaid balance problem, not a decision. Removing them instantly converts a recoverable lapse into a lost member and a support message.
A grace period is cheap and works.
| Grace | Effect |
|---|---|
| 0 days | Maximum churn, maximum support load. Avoid. |
| 3 days | Good default. Covers "I'll top up later." |
| 7 days | Generous. Reasonable for high-value channels and long-tenured members. |
| 14+ days | Too long. Teaches people the deadline isn't real. |
Three days is the sensible default. Long enough to top up, short enough that the subscription still means something.
Tenure-based grace
Not every lapse deserves the same treatment. An eight-month member and a first-month member are different situations.
| Tenure | Grace |
|---|---|
| First period | 3 days |
| 3+ months | 5 days |
| 12+ months | 7 days, plus a personal message |
Your longest-standing members are your most valuable and your least likely to be gaming anything. Treating them identically to a day-one signup is a small cruelty with a real cost.
Say it before you do it
Most anger about removal is not about the removal. It is about surprise.
Before: "Your subscription lapsed. You have 3 days to top up before access ends."
On removal: "Your access to [Channel] has ended. Rejoin any time here — you'll be back immediately."
The second message is what separates a lost customer from a returning one. Make it clear that rejoining is trivial and that nothing was held against them. Never remove someone silently — silence reads as a technical fault, and they will tell people your bot is broken.
The checklist
- Always pass
only_if_banned=TruetounbanChatMember - Never compute a
until_datethat could land under 30 seconds - Don't revoke the primary invite link during routine operations
- Warn before removing, always
- Default to 3 days' grace, more for long-tenured members
- Make rejoining one tap
- Log every removal with the reason — you will need it when someone asks
The API details matter more than the policy here. A generous grace period cannot save you from a cleanup job that silently ejects paying members.
API behaviour quoted from Telegram's Bot API documentation, verified September 2026. Method behaviour changes — re-check before implementing.