A member stops appearing in your paid channel and the dashboard moves them to churned, so you assume they decided something.
Often nobody decided anything. A card expired, or a bank declined a renewal at three in the morning, and a countdown started that the member could not see. How long that countdown runs, whether anyone tells them it is running, what happens at the end of it and how they get back afterwards are four separate decisions. Your payment processor makes none of them. Someone at the company you sell through made all four, in a file no seller will ever read.
We wrote one of those files. Between April and June 2026 we built Volta, a platform for creators selling access to a Telegram channel. It was ours, we retired it in August, and handling failed renewals was harder than taking the money in the first place. Here is what each of the four decisions does, including the one we got wrong.
The countdown is a number somebody typed
Ours was 72 hours. A renewal fails, Stripe sends invoice.payment_failed, we move the
subscriber into a grace state and queue three retry jobs at 24, 48 and 72 hours. If none
of them collects, a fourth job removes the member from the channel. That is the entire
grace period. It was chosen in a planning document, written into a worker, and appears
nowhere a buyer could read it.
Stripe would have suggested something different. Its Smart Retries setting takes a number
of attempts and a window of 1 week, 2 weeks, 3 weeks, 1 month or 2 months, and the
recommended default is 8 attempts within 2 weeks. A custom schedule allows up to three
retries.[1] We ran our own instead, calling invoices.pay on our
own timer, because we wanted the grace state and the messaging to be ours. So we rebuilt a
dunning system that already existed, to shorten it by eleven days.
Other platforms picked other numbers. Memberful retries up to four times, always 12 hours apart, and deactivates the subscription if it cannot charge after 48 hours.[2] Kajabi revokes access to the offer when the retries are exhausted on Kajabi Payments, while on PayPal the customer keeps access until the recurring payment is cancelled or revoked by hand.[3]
One declined card. Two days on one platform, three on ours, a fortnight on the recommended Stripe default, and on one path an access grant that stays open until a human notices. None of that is a property of the card, or the bank, or the decline code.
The end of the countdown is a further setting. A Stripe subscription can be told to cancel,
to become unpaid, or to sit in past_due indefinitely with invoices still
generating.[1] That choice decides whether a member who fixes
their card in week three resumes the subscription they already had or has to buy a new
one, which is not a small difference when the thing being resumed is a price you have
since raised.
Whether the member finds out is a checkbox
Stripe will email the customer when a card payment fails, once someone enables Send emails when card payments fail. It will warn them a month before a card on file expires, once someone enables that separately. Those emails carry the branding of the account sending them.[4]
We could use neither. Our buyers were Telegram users and most had never given us an email address, so the notification was a bot message we wrote ourselves and sent on the first retry only:
Your subscription payment for
{offer}failed. Update your payment method to keep access:{link}
The second and third retries were silent. And that message could fail to arrive. A buyer
who had blocked the bot, or who had never opened a chat with it, simply never got it. We
caught the error, wrote a dm_failed_at timestamp into the subscriber row, and let the
retries continue.
That timestamp did nothing. Nobody was alerted, no fallback was attempted, and the creator was not told that one of their members was three days from removal and could not be reached. For those members the grace period was not a recovery window, it was 72 hours of silence and then a locked door. Building it again, an undeliverable dunning message would be an event the seller sees, because it is the only moment when a human who knows the member personally can still do something.
Worth asking of whatever platform you sell on: what does a member receive when a renewal fails, how many times, and whose name is on it. On a platform built with Stripe Connect the customer record belongs to the platform, so any of those built-in emails go out under the platform's branding and support address rather than yours.
Some declines were never going to succeed
Stripe will not retry at all if the issuer returned a hard decline code. The list includes
lost_card, stolen_card, incorrect_number, pickup_card, authentication_required
and transaction_not_allowed. The scheduled retries stay on the calendar and
attempt_count keeps incrementing, but nothing is actually attempted until a new payment
method appears.[1]
A member whose wallet was stolen therefore gets a grace period made entirely of appearances. Three retries fire, three log lines appear, and no charge is ever presented to a bank. The only thing that can recover that subscription is the member replacing the card, which means the only thing that can recover it is the message.
Retries recover the temporary problems: the balance that was short on Tuesday and fine on Thursday. Everything else is recovered by telling somebody, or not at all. We built the retries carefully and the message casually. That is backwards, and it is the ordinary way round for engineering teams, because retries are the part you can test.
Removed is a request to somebody else's software
When our countdown ran out, a worker called Telegram's banChatMember. That call requires
the bot to be an administrator in the channel with the appropriate rights.[5]
Creators are administrators of their own channels and can remove a bot's rights at any
time, for any reason, and we would not find out until the next time we needed them.
So we handled the failure. If Telegram answered 400, we logged it, messaged the creator to
say we could not remove the member and they would have to do it themselves, and then
marked the subscriber as banned in our database anyway, with a comment explaining that
this kept the dashboard consistent.
Consistent, and wrong. The dashboard now said the member was removed. The member was in the channel, reading everything, paying nothing. We had written down our intention and displayed it as an outcome, and those two things come apart exactly when something has gone wrong, which is the moment a seller is relying on the number.
The right shape is a state that says the removal failed and stays visible until somebody resolves it. Anyone selling access through software they do not own has the same problem in a different costume: a Discord role, a private repository, a course login, a Slack workspace. In all of them the platform can only ask, and the thing actually holding the door belongs to someone else.
Getting back in is not automatic
The Telegram documentation is unusually blunt about what a ban means. A banned user "will
not be able to return to the chat on their own using invite links, etc., unless unbanned
first".[5] Unbanning does not undo the removal either: the user
"will not return to the group or channel automatically, but will be able to join via
link", and calling it on somebody who is currently a member removes them, unless the
only_if_banned flag is passed.[6]
Recovery is therefore three steps in a fixed order. Take the payment, lift the ban, issue a new invite. Miss the middle one and you have a member who has paid you twice and cannot get through the door, which they will experience as a scam rather than as a bug. Ours did all three. The point is that it had to be built, deliberately, by someone who had read that paragraph.
One question is worth asking before you move a membership onto a platform: what exactly happens when a lapsed member pays again on day ten. The answer either has steps in it or it does not.
The two things in the churn column
Every dashboard adds them together. A member who cancels has told you something about your product: the price, the posting rate, the thing you promised in the sales page and did not deliver in the channel. A member whose card expired has told you something about a retry schedule, a notification checkbox and an access-control call, none of which they know exist.
The first kind is expensive to fix and worth fixing. The second is a settings page, somebody else's, and you can usually just ask.
Disclosure. Volta was our product, it is retired, and nothing here is a recommendation
to use it. The 72-hour grace period, the retry worker, the wording of the DM, the
dm_failed_at timestamp that went nowhere and the decision to mark a failed removal as
done are all from our own implementation rather than anyone's documentation, so they carry
no citation below. Everything attributed to Stripe, Memberful, Kajabi or Telegram is
quoted from their own public documentation, listed and dated at the bottom of this page.
