DEV Community

Alex Manner
Alex Manner

Posted on

How to Set Up Recurring Payments for a Telegram Channel

description: Build Telegram recurring payments with monthly and annual plans, renewals, dunning, cancellations, and predictable access expiration.

For example, a subscriber has paid for channel access until September 30 and turns off renewal on September 10. He or her needs to know whether another payment will be taken and how long they can keep using the channel. Decide what happens in that situation before setting up automatic billing.

A failed renewal raises a different question: how much time does the subscriber have to fix the payment before losing access? That depends on the retry schedule and any grace period you offer.

This guide is about those billing decisions: monthly and annual plans, successful renewals, failed payments, cancellation, and expiration. It focuses on deciding when access should continue or end; the Telegram admission and removal workflow belongs in a separate access-automation guide.

1. Define the Billing Contract First

Before choosing a payment service provider (PSP), settle the terms of your Telegram recurring subscription:

  • Does billing run every 30 days, each calendar month, or once a year?
  • What is the price, and which currency will the subscriber pay in?
  • Does the subscription renew automatically?
  • Is there a trial, and how long does it last?
  • How long can access continue after a renewal payment fails?
  • Does cancellation take effect immediately or at the end of the paid period?
  • How will you handle refunds and payment disputes?
  • At exactly what date and time does access end?

Use the same terms at checkout, in customer messages, and in your billing logic.

For example, “monthly” is ambiguous. Telegram's native channel subscription period is 2,592,000 seconds—exactly 30 days. A card-based PSP may instead support calendar-month billing anchored to a specific day. Those schedules drift apart over a year.

Store timestamps in UTC and render them in the subscriber's local timezone. Otherwise a cancellation shown as “active through October 1” can expire several hours earlier than the customer expects.

2. Treat Monthly and Annual Plans as Different Products

Monthly and annual plans should have separate price IDs, billing intervals, and reporting.

Decision Monthly plan Annual plan
Customer commitment Lower Higher
Renewal attempts Usually 12 per year Usually 1 per year
Exposure to involuntary churn Higher Lower
Cash collected upfront Lower Higher
Refund exposure Lower Higher
Speed of retention feedback Faster Slower

At $15 a month, twelve months cost $180. A $150 annual plan saves the subscriber $30—the equivalent of two monthly payments, or about 16.7%.

You receive the payment upfront and have fewer scheduled renewals to handle. But you also collect $30 less from a subscriber who would otherwise pay for all twelve months. Decide whether that trade-off works for your channel before setting the discount for the purchase of an annual subscription.

Do not confuse these offers:

  • Annual recurring subscription: the PSP is authorized to attempt another annual charge at the next renewal.
  • One-time annual access: one payment creates 12 months of access, with no future charge.

The second offer is prepaid access, not recurring billing. Label it clearly in checkout, receipts, and cancellation terms.

Also separate cash collection from normalized subscription metrics. An annual payment improves current cash flow, but for product analytics you may still normalize it to monthly recurring revenue (MRR). Annual recurring revenue (ARR), cash collected, and recognized revenue are different figures.

3. Choose the Payment Rail

There are three practical ways to run Telegram recurring payments.

Route Billing capability Operational owner Best fit
Native Telegram Stars Fixed 30-day channel subscription Telegram One channel and one simple recurring cycle
Managed membership platform Depends on the platform and connected PSP Platform plus PSP Teams that do not want to operate billing and access jobs
Custom bot plus PSP Provider-specific monthly, annual, trial, and pricing options Your team Custom entitlement or back-office requirements

Telegram's createChatSubscriptionInviteLink currently accepts only 2592000 seconds as subscription_period, and the target must be a channel. It is suitable for a basic monthly Telegram subscription, but not for a native annual cycle or a bundle of several resources.

If a bot or Mini App sells digital goods or services inside Telegram, Telegram requires payment in Stars (XTR). A card form embedded in a Mini App does not become compliant merely because Stripe, PayPal, or another PSP processes it. Review Telegram's Stars payment rules before designing the checkout path.

Managed platforms such as Nemiling, InviteMember, Tribute, and LaunchPass can combine billing with Telegram access management. The supported periods, currencies, PSPs, retries, and resource types vary. Nemiling is relevant when you need several Telegram monetization formats and supported external PSPs without maintaining the entire webhook and access stack yourself.

A custom integration makes sense when you need corporate seats, CRM rules, usage credits, custom dunning, multiple products, or access outside Telegram. It also makes your team responsible for payment authorization, webhook security, retry policy, reconciliation, refunds, and incident recovery.

If you are still selecting that layer, see Best Telegram Monetization Platforms in 2026.

4. Create a Reusable Payment Authorization

A recurring card payment is not a cron job that charges a card number every month.

During the initial checkout, the PSP should create a customer, store the payment method in its vault, collect the required consent for future off-session charges, and create the subscription. Your database stores provider IDs—not PAN, CVC, or raw card details.

A minimal billing record can look like this:

CREATE TABLE subscriptions (
  id                         UUID PRIMARY KEY,
  membership_id              UUID NOT NULL,
  provider                   TEXT NOT NULL,
  provider_customer_id       TEXT NOT NULL,
  provider_subscription_id   TEXT NOT NULL,
  provider_price_id          TEXT NOT NULL,
  billing_interval           TEXT NOT NULL,
  status                     TEXT NOT NULL,
  current_period_start       TIMESTAMPTZ,
  current_period_end         TIMESTAMPTZ,
  cancel_at_period_end       BOOLEAN NOT NULL DEFAULT FALSE,
  next_retry_at              TIMESTAMPTZ,
  grace_until                TIMESTAMPTZ,
  last_paid_invoice_id       TEXT,
  updated_at                 TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  UNIQUE (provider, provider_subscription_id)
);
Enter fullscreen mode Exit fullscreen mode

membership_id links billing to a separate entitlement record. That boundary matters: the PSP decides whether money was collected; the entitlement service decides whether access is currently valid.

Some renewals require Strong Customer Authentication (SCA), 3DS, or another customer action. For Stripe, invoice.payment_action_required is a signal to send the subscriber to a hosted authentication or payment-update flow. Do not treat it as a successful renewal, and never ask for card details inside Telegram chat.

5. Map Provider Events to Billing Decisions

For a Stripe-based implementation, the core event mapping is usually:

Event Billing update Access decision
invoice.paid Store the paid invoice and authoritative period end Extend entitlement
invoice.payment_failed Set past_due; record retry data Keep or expire access according to grace policy
invoice.payment_action_required Mark customer action required Keep temporary access only if policy allows it
customer.subscription.updated Sync plan, status, dates, and cancellation flag Recalculate paid-through time
customer.subscription.deleted Mark subscription non-renewing/terminated Do not revoke blindly; check the paid-through timestamp

Stripe documents these events in its subscription webhook guide. Other PSPs use different names, so map their events into your own internal vocabulary instead of leaking provider statuses throughout the codebase.

Webhook handling still needs two safeguards:

  1. Verify the provider signature and store every event ID under a unique constraint.
  2. Expect duplicate and out-of-order delivery. Before shortening a paid period or changing a terminal state, retrieve the latest subscription or invoice from the PSP.

Keep this layer small. Persist the billing change, enqueue follow-up work, and return a successful HTTP response quickly. Telegram API calls should not block the PSP webhook.

6. Use the Provider's Renewal Boundary

Never calculate the next expiration date by adding 30 or 365 days locally.

Pauses, late retries, billing-anchor changes, trials, and plan migrations can move the boundary. On invoice.paid, read the authoritative period from the provider and replace current_period_end with that value.

A successful renewal handler should:

  1. verify that the invoice is paid;
  2. confirm which subscription and price it belongs to;
  3. reject a duplicate invoice using last_paid_invoice_id or another idempotency key;
  4. update the provider's current period dates;
  5. clear next_retry_at and grace_until;
  6. mark the billing status active;
  7. publish an entitlement_extended job or domain event.

Renewal does not require a new Telegram invite when the member is already present. It only moves the paid-through boundary.

If you support upgrades or downgrades, decide whether changes apply immediately with proration or at the next renewal. Do not rely on the PSP dashboard default without documenting it; otherwise the checkout copy and the invoice can describe different outcomes.

7. Design Dunning Before the First Failure

Dunning is the recovery process for an unpaid renewal: retry scheduling, notifications, authentication, payment-method updates, and final expiration.

An example policy might be:

Stage Billing action Subscriber experience
First failure Set past_due; read provider retry schedule Warning plus hosted payment-update link
Retry window Let the PSP retry eligible failures Access remains during grace period
Customer action required Pause blind retries until the user authenticates or updates payment data Direct CTA with an exact deadline
Final failure Set expired; stop expecting renewal Access expires at grace_until

Decide how long a member can keep access after a renewal payment fails. A longer grace period gives them more time to fix the problem, but also means providing access while the renewal remains unpaid. Track how many members renew before the deadline and use that result to decide whether the grace period should be shorter or longer.

Use decline information correctly:

  • Soft decline: a temporary problem such as insufficient funds or an issuer outage may succeed later.
  • Hard decline: an invalid or blocked payment method usually requires customer action before another useful attempt.

Stripe's Smart Retries can choose retry timing and expose the next planned attempt. If the PSP owns that schedule, do not run an independent charging cron against the same invoice. Two retry controllers can generate duplicate attempts and contradictory messages.

When a renewal fails, tell the subscriber what happened and what they need to do. The notification should explain:

  • which renewal payment failed;
  • whether another automatic attempt is scheduled;
  • where to authenticate the payment or update the payment method, using a link to the hosted page;
  • the exact date and time when access will end if the payment remains unresolved;
  • how to contact support if they can already see the payment in their account.

The subscriber should be able to act on this message without having to ask when access ends or whether the system will try charging them again.

8. Separate Cancellation, Expiration, and Refunds

A subscriber can stop future charges, reach the end of paid access, or receive a refund. Define what each action changes in your system.

Cancel at period end

When a subscriber turns off renewal at period end, set cancel_at_period_end = true and keep access available until current_period_end. Show that date in the cancellation confirmation.

For an annual plan, this usually stops the next year's charge. Whether unused months are refunded is a separate question. Make those terms clear before the customer pays.

Cancel immediately

Immediate cancellation stops recurring billing now. Whether access ends at the same time depends on your policy and any refund issued.

You might use this flow after a full refund, confirmed fraud, abuse, or an administrator's decision to end the subscription. Define the access outcome for each case.

Refund or dispute

Canceling a subscription does not itself return a payment. Issuing a refund does not necessarily stop future subscription charges. A chargeback may also arrive after the subscriber has already used the access they paid for.

Handle these as separate operations, with explicit rules for how they affect billing and access. When issuing a refund, check whether the subscription should continue. When canceling it, check how much paid access remains.

For Stars subscriptions created through a bot, editUserStarSubscription can cancel or re-enable subscription extension. For a native channel subscription link, Telegram manages the channel subscription lifecycle.

9. Hand Expiration to the Access Layer

The billing service should produce a clear output, not manipulate Telegram membership in the middle of invoice processing.

One practical rule is:

access_valid_until = max(
  current_period_end,
  grace_until ?? current_period_end
)
Enter fullscreen mode Exit fullscreen mode

Use grace_until only when a grace policy is active. Fraud, a full refund, or an administrator action may intentionally override this formula.

When the deadline passes, emit an entitlement_expired event. The access component can then remove the member, retry Telegram API failures, and record completion. That implementation belongs in an access-automation guide; repeating it here would obscure the recurring-billing problem.

The handoff differs by architecture:

  • Native channel subscription link: Telegram manages payment-linked membership.
  • Managed membership platform: the platform usually owns billing-to-access synchronization.
  • Custom PSP integration: your billing service publishes the decision and a separate worker applies it to Telegram.

The important invariant is simple: cancel_at_period_end is not expiration, and past_due is not necessarily expiration. Revoke access only after the paid period and applicable grace period have ended.

10. Test the Renewal Path, Not Only Checkout

Use a sandbox or test environment to check what happens in each of these situations:
• A new subscriber completes the first payment.
• The first monthly renewal succeeds.
• An annual subscription renews at the correct price and for the correct period.
• A renewal requires the subscriber to complete SCA or 3DS authentication.
• A temporary payment failure succeeds on a later retry.
• A hard decline requires a new payment method before renewal can succeed.
• The same webhook arrives twice.
• An older webhook event arrives after a newer one.
• A subscriber upgrades, and the expected prorated charge is applied.
• A subscriber turns off renewal but keeps access for the rest of the paid period.
• An immediate cancellation applies the intended access and refund rules.
• A refund is issued while the subscription is still active; confirm whether another charge is intended and prevent it if it is not.
• A delayed successful payment arrives just before access is due to expire.
• An expiration timestamp stored in UTC is displayed correctly in different timezones, including across daylight-saving changes.

Stripe provides test cards, webhook tooling, and test clocks for subscription scenarios. Telegram maintains a separate test environment for Stars payments.

11. Measure Billing Quality

New subscribers can keep total membership growing even while existing members fail to renew. Check how often renewals succeed, which failed payments you recover, and why subscriptions end. Track:

  • renewal success rate: successful renewal invoices divided by invoices due;
  • involuntary churn: subscriptions lost because payment could not be recovered;
  • retry recovery rate: failed renewals later paid successfully;
  • grace-period recovery rate: past-due subscribers recovered before expiration;
  • voluntary churn: subscribers who intentionally disabled renewal;
  • net MRR movement: new, expansion, contraction, reactivation, and churned MRR;
  • time to entitlement expiration: delay between the final billing decision and the access deadline.

Segment the metrics by PSP, payment method, currency, country, billing interval, and plan. A healthy annual plan can hide a weak monthly renewal flow if everything is aggregated.

Final Rule

Before launching a monthly Telegram subscription, make sure you can answer four questions: when will the next charge happen, what happens if it fails, what changes when the subscriber cancels, and exactly when does access end? Check that your checkout, customer messages, and billing rules give consistent answers.

Keep the responsibilities clear. The PSP confirms payment status and billing periods. Your subscription record tracks the paid-through date and any applicable grace period. The access component AIapplies the resulting decision to Telegram. This gives you a clear path to investigate a failed renewal or an unexpected removal.

Top comments (0)