DEV Community

Alex Manner
Alex Manner

Posted on

How to automatically grant Telegram access after payment

A customer pays for your private Telegram community. The payment succeeds, but the invitation fails because the bot has lost an administrator permission. What should happen next?

The customer should keep their purchased access, and the system should retry delivery. Charging them again would turn an operational failure into a billing problem.

Disclosure: the worked example is illustrative; no live integration was tested for this article.

This article describes an architecture for connecting confirmed payments to Telegram access. It follows one order through payment, admission, renewal, and expiration. The examples illustrate the design; they are not a complete application or a live-tested integration.

Follow one order through the system

Maya buys 30 days of access to a private community. Her example Telegram user ID is 123456789, and her order is order_123.

For this example, the purchased period begins when payment succeeds: November 1, 2026, at 10:00 UTC. It ends on December 1, 2026, at 10:00 UTC.

Keep three questions separate:

Question Application state
Was the order paid? Payment record
Is Maya currently entitled to this community? Entitlement record
Has she actually joined, or does admission need attention? Admission and membership state

A payment can be confirmed while admission remains pending. Maya can also leave voluntarily while her entitlement remains valid.

The field names below belong to this example application. They are not a universal payment-provider schema.

1. Choose the payment route

For digital goods and services sold inside Telegram bots or Mini Apps, Telegram requires Telegram Stars, using the currency code XTR. Owning an external website does not exempt an in-app sale from that requirement. The official digital payments guide explains the supported flow.

With a bot invoice, approving a pre-checkout query does not confirm payment. Wait for successful_payment before granting the purchase, and retain its telegram_payment_charge_id for payment operations such as refunds.

An independent website checkout has its own provider integration and rules. Do not assume that a payment route suitable for a website can simply replace Stars inside a bot.

Telegram also offers native paid channel subscription links. That is a separate flow from the custom entitlement and admission system discussed here. Decide which model you are implementing before combining their behavior.

2. Bind the order to a verified recipient

A numeric Telegram ID identifies an account, but accepting a number typed into a checkout form does not establish who is using that account.

One possible flow is:

  1. Maya starts your bot.
  2. Your server identifies her from an authenticated Telegram update.
  3. Your server creates an order linked to that identity and the selected community.
  4. The payment integration refers back to that server-side order.

For a website handoff, use an expiring, unguessable order token bound to the server-side identity. Check the binding on the server. Do not trust a recipient ID merely because the browser submits it.

Before payment, a simplified order might look like this:

{
  "order_id": "order_123",
  "recipient_telegram_user_id": 123456789,
  "community_id": "community_01",
  "payment_status": "pending",
  "paid_through": null,
  "admission_status": "not_started"
}
Enter fullscreen mode Exit fullscreen mode

Store the expected product, amount, currency, and provider references as well. They are omitted here to keep the example readable.

For gifts, model the payer and recipient separately. Define how the recipient claims the purchase rather than assuming that the account making the payment receives the access.

3. Record payment before attempting admission

The browser's success page is useful feedback, but it should not be the authority that grants access.

Authenticate the server-side notification using the mechanism supported by its source:

  • For Stripe, follow its webhook signature verification procedure, preserving the raw request body.
  • For a Telegram webhook, configure secret_token and validate the X-Telegram-Bot-Api-Secret-Token header described in setWebhook.

These mechanisms are different; the Telegram header is not a Stripe-style payload signature. Keep their secrets on the server.

After authentication, durably record the notification, then acknowledge it. A background worker can validate the order, payment state, amount, and currency before updating access. If durable storage fails, do not acknowledge the notification as successfully accepted.

The worker should commit the entitlement change and a pending access task together. Otherwise, a crash after recording payment but before scheduling admission can leave a paid customer without a delivery attempt. A database-backed task or transactional outbox is one way to close that gap.

After processing Maya's payment, the simplified view becomes:

{
  "order_id": "order_123",
  "recipient_telegram_user_id": 123456789,
  "community_id": "community_01",
  "payment_status": "confirmed",
  "paid_through": "2026-12-01T10:00:00Z",
  "admission_status": "pending"
}
Enter fullscreen mode Exit fullscreen mode

Handle duplicates and older events separately

Stripe documents both duplicate notifications and events delivered out of order. These require different safeguards.

For duplicates, record event identifiers and enforce a unique business operation for each access grant. Depending on your billing model, that operation might represent a paid invoice period or a specific purchase. Two workers must not both extend access for the same purchase.

For events arriving out of order, an older notification must not overwrite newer entitlement state. Use the provider's relevant payment or subscription state and your recorded grant history to decide the transition. Where necessary, retrieve the current provider object. Event arrival order is not a reliable billing timeline.

For Maya, receiving the same payment twice must still produce one purchased period. Receiving an older notification after a later renewal must not erase that renewal.

4. Admit the intended recipient

The bot needs administrator permissions appropriate to invitation and removal operations. Configure these before accepting purchases.

In this design, it creates an invitation with creates_join_request=true. Maya follows the link and requests admission; the bot does not silently insert her into the community.

The application checks the requesting account, target community, and current entitlement before calling approveChatJoinRequest. A forwarded link alone must not grant access to another account.

Do not combine creates_join_request=true with member_limit. Also, member_limit=1 limits simultaneous members through a link; it does not make the link permanently single-use. See createChatInviteLink.

Apply the entitlement check to all admission paths you control. An unmonitored direct invitation or manual approval can bypass the application's checks.

5. Recover from failed delivery

Suppose the invitation task fails because the bot has lost a permission.

Keep Maya's payment confirmed and her purchased entitlement recorded. Mark admission as needing attention, retain the failure details, and retry after the permission is restored. Do not create a second charge or extend the period merely because a delivery task runs again.

In this example, access time starts at payment. If a service failure delays delivery, support needs a defined remedy, such as an extension or refund. Alternatively, you could design a period that starts at admission, but that requires its own activation and expiration rules.

An operator should be able to find order_123, see what succeeded, identify the failed step, and retry delivery without editing billing history.

6. Separate renewal from the paid period

Maya turns off automatic renewal on November 12. She keeps her purchased access until December 1 at 10:00 UTC.

Here, paid_through is an application field representing the end of her granted period. Turning renewal off does not clear that date or move it backward. A provider may use different field names and cancellation semantics, so map its events to your own explicit policy.

For normal expiration, use a precise boundary:

period_is_current = now_utc < paid_through
Enter fullscreen mode Exit fullscreen mode

At exactly paid_through, the period has ended. Store timezone-aware timestamps and compare instants consistently.

The date is only one part of the access decision. Refunds, payment disputes, and administrative restrictions need separate rules. A partial refund, for example, should not automatically be interpreted as cancellation of all access unless that is your defined policy.

If one person has multiple valid grants for the same community, evaluate their combined entitlement before removing them.

7. Coordinate expiration with renewal

An expiration task should load the current entitlement before attempting removal. If Maya has renewed, an old task must not revoke her new period.

However, checking immediately before the API call does not eliminate every race. A renewal can arrive between that check and the removal request.

Coordinate grant and removal operations for each user–community pair, and reconcile the result when concurrent changes occur. A per-member work queue can help, provided all relevant access operations follow the same coordination mechanism. A database transaction alone cannot make a Telegram API request atomic with your database update.

Record removal attempts and retry failures. If a concurrent renewal leaves a valid customer outside the community, restore their ability to join and notify them rather than leaving the discrepancy unresolved.

When using unbanChatMember to lift a prior ban, consider only_if_banned=true: without it, an existing member can be removed. Unbanning does not automatically rejoin the user.

8. Reconcile intended access with actual delivery

Retries handle known failures. A periodic reconciliation process helps identify work that was missed or never completed.

Look for confirmed purchases without entitlement processing, valid entitlements with stalled admission, and expired entitlements with unfinished removal tasks. Where supported and permitted, check the membership of known users instead of assuming that an old API result still describes the present.

This is also useful when an API request times out: the operation may have succeeded even though your worker did not receive the response. Check the resulting state before deciding the next action.

If you use a managed platform, ask how it handles these same cases: confirmed payment with failed admission, duplicate events, and renewal during removal. A normal successful checkout does not demonstrate recovery behavior.

Test the transitions

Use a test community and the relevant payment test environment before accepting real purchases. The following are proposed checks, not results from a tested implementation.

Scenario Expected outcome
Payment succeeds; invitation fails One confirmed purchase, entitlement retained, delivery task pending or failed
Same payment notification arrives twice One access grant; no duplicate period extension
Two workers process the same purchase The database permits only one grant for that business operation
An older event arrives after renewal The valid renewed entitlement remains intact
Maya forwards her invitation An account without the required entitlement is not approved
Renewal is disabled on November 12 Access remains valid until December 1 at 10:00 UTC
The expiration boundary is reached The period is no longer current; removal follows the defined policy
Renewal arrives during removal The system resolves the conflict and restores eligible access if removal occurred
Telegram request times out The worker checks the result before deciding whether to repeat the action
A refund or dispute arrives The explicit policy is applied without losing the original payment history

Conclusion

For order_123, successful payment creates a recorded entitlement. Admission delivers it, and expiration ends it according to the chosen policy. Each step can fail independently.

Reliable automation preserves that distinction: it records purchases once, checks who should receive access, and recovers when Telegram and the application's intended state diverge.

Top comments (0)