§Use caseOne operator

Keep paywall access honest

A Stripe-plus-bot integration usually does one thing: catch the webhook, flip a flag. That holds right up until a webhook is missed, retried twice, or arrives out of order, which Stripe's own docs say will happen. Below is how I build it so a missed or doubled event never leaves a subscriber locked out, or a canceled one still inside.

All three trigger chains, and the setup written on the canvas
All three trigger chains, and the setup written on the canvas
The whole Stripe-to-Telegram paywall workflow on the n8n canvas: the webhook chain, the daily reconciliation chain, and the bot's own lookup.

The questionHow do I gate a Telegram bot behind Stripe without a subscriber's access drifting from what they actually paid?

How the working version is put together

  1. Check every event once

    A Stripe webhook chain reacts to checkout completions, subscription updates and cancellations. Before anything else runs, I check the event ID against a ledger table. Stripe delivers webhooks at least once, sometimes twice for the same event, and this is what stops a retried delivery from double processing.

  2. Cut the grace period on cancellation

    A cancellation or a past-due status flips access off immediately, with no grace period. I built it this way on purpose. A webhook telling me a subscription is gone is not a moment for leniency, and a lapsed grace period is exactly how a canceled subscriber keeps reading a paid channel.

  3. Map the event, then write one row

    I map the Stripe event to a tier and an active flag with a code step, then upsert it into an entitlement table keyed on the Telegram user. One row per subscriber, holding their tier, whether they are active, and whether a webhook or the daily reconciliation last touched it.

  4. Ask Stripe again, once a day

    This is the part a webhook-only build never has. Once a day I read every entitlement row and ask Stripe directly what that subscription's status actually is right now. A webhook can be missed, retried into a dead end, or simply never arrive. Whichever direction the drift runs, this catches it here.

  5. Correct it and name it, never swallow it

    A drifted row gets corrected and the correction is reported by name in Slack, not absorbed silently. A clean sweep with nothing drifted reports nothing further, because a report with nothing wrong in it does not need writing.

  6. Let the bot ask one question only

    The Telegram bot itself never talks to Stripe. It only ever asks the entitlement table one question: is this user active. Whatever else is happening with webhooks or reconciliation, the bot's answer stays a single fast lookup.

The kit

Gate a Telegram bot behind Stripe and never let access drift from what's actually paid for

I built and gated this one, staging for Etsy now: 22 nodes across three independent triggers, the setup written on the canvas, and a setup guide for every node. If you want it sooner, or set up around your own Stripe and Telegram accounts, start a brief instead.

What the webhook-only version actually costs

I have watched the simple version of this fail quietly more than once. A subscriber cancels, the webhook never arrives because a queue dropped it or an endpoint timed out for a minute, and the bot has no way of finding out. Nobody notices until someone flags that a canceled subscriber is still reading the channel.

The other direction costs money in a different way. A subscriber pays, the webhook is late or duplicated, and they message you confused about why the bot has not let them in yet. Either failure reads as a bug in the bot, when the real gap is that I had nothing checking the webhook's work.

The parts that break

Stripe's own at-least-once delivery is the first one I watch for. A webhook can arrive twice for the same event, and a build that flips a flag on receipt rather than checking an event ledger first will double-process it, sometimes harmlessly and sometimes not.

A missed webhook is the second, and it is the one that stays invisible. Nothing in Stripe tells you a webhook silently failed to reach your server. The only way I know of to catch it is to ask Stripe directly on a schedule, which is the entire reason the reconciliation chain exists.

What it costs to run

Close to nothing. Every check reads a Data Table row or calls Stripe's own API once a day per subscriber, so the running cost is whatever your automation platform already costs you, and I put no model call anywhere in this build.

The real cost is judgment, once: picking the reconciliation schedule and the past-due grace window that match how your customers actually pay, then reading the Slack report the first few times it fires.

Why take this from me

Because I sell access to bots and communities the same way, and I built this after watching the simple version of the pattern fail quietly on somebody else's setup. The work below links to systems I actually run, and Booboo, the operational brain behind them, is open source so you can read how I build before paying me anything.

The fair objection is that this is my own operation rather than a client roster, and there are no reviews on this site because I do not have any yet. I would rather say that here than have you notice it.

Read this before you spend anything

Who should not buy this

If your Telegram bot has no paid tier at all, there is nothing here to gate and I would say so rather than take the work.

If you are fine with access drifting until a subscriber complains, and that has genuinely never cost you a refund or an awkward conversation, this solves a problem you do not have yet.

What lands on your desk

  • I set it up inside your own n8n, on your own Stripe account and your own Telegram bot, under your own credentials
  • The two Data Tables written and wired: one ledger for processed Stripe events, one entitlement row per subscriber
  • The daily reconciliation schedule and the past-due grace window set to match how your customers actually pay
  • A Slack report that names every correction by subscriber, so a clean day writes nothing and a bad one is never silent
  • A walkthrough I write down, so whoever touches it next is not dependent on me

Questions this page answers

What stops a retried Stripe webhook from double-processing?
Before anything else runs, I check the event ID against a ledger table. An event already seen is a no-op, which is the whole idempotency guarantee against Stripe's at-least-once delivery.
What happens if a webhook never arrives at all?
The daily reconciliation chain catches it. Once a day I read every entitlement row and check it against Stripe directly, and a drifted row gets corrected and reported by name.
Is there a grace period after a subscription is canceled?
No. A cancellation or a past-due status flips access off immediately. A webhook telling me a subscription is gone is not a moment for leniency.
Does the Telegram bot itself call Stripe?
Never. It only asks the entitlement table one question, active or not, so replying to a user stays a single fast lookup regardless of what else is happening with webhooks or reconciliation.

Want this built and handed over working?

One line is enough to start. You get an honest answer on fit, and a number rather than a discovery call.

Start a brief