Build a Telegram bot that sells group access with M-Pesa
How paid Telegram groups work with M-Pesa STK Push: one-time invite links, join requests, automatic expiry and the edge cases to handle.
Philip Egesa 3 min read
Signal providers, coaches and communities across Kenya charge for access to private Telegram groups. Doing it by hand means checking M-Pesa messages, sending invite links, and remembering to remove people when their subscription ends. A bot can do all of it.
Here is the design we use.
The flow
- A member sends
/jointo your bot. - The bot shows plans with inline buttons (for example 1 week or 1 month).
- The member taps a plan and shares their M-Pesa number.
- Your server sends an STK Push. The member enters their PIN.
- When the M-Pesa callback confirms payment, the bot sends a single-use invite link.
- Before expiry, the bot sends a renewal reminder. After expiry, it removes the member.
Setting up the bot
Create the bot with @BotFather and keep the token secret. Add the bot to your private group or channel as an administrator with permission to invite users and ban users. Without those rights it cannot create invite links or remove members.
Use a webhook in production, so Telegram pushes updates to your HTTPS endpoint, rather than polling.
Showing plans with inline buttons
await bot.sendMessage(chatId, "Choose a plan to join the members group:", {
reply_markup: {
inline_keyboard: [
[{ text: "1 week · KES 500", callback_data: "plan:week" }],
[{ text: "1 month · KES 1,500", callback_data: "plan:month" }],
],
},
});
When the member taps a button, you receive a callback_query. Ask for their M-Pesa number (or use a saved one), then start the STK Push exactly as in our Daraja STK Push guide. Store the Telegram user ID with the pending payment.
Granting access safely
After a successful callback, create an invite link that only works once and expires quickly:
const expire = Math.floor(Date.now() / 1000) + 60 * 30; // 30 minutes
const link = await bot.createChatInviteLink(GROUP_ID, {
member_limit: 1,
expire_date: expire,
name: `sub-${subscriptionId}`,
});
await bot.sendMessage(telegramUserId, `✅ Payment confirmed. Join here: ${link.invite_link}`);
Single-use, short-lived links stop members from sharing access.
An even tighter option is join requests. Create the link with creates_join_request: true. When someone taps it, Telegram sends your bot a chat_join_request. The bot approves it with approveChatJoinRequest only if that Telegram user has an active subscription, and declines everyone else.
Expiry and removal
Run a scheduled job (for example every 15 minutes) that:
- Sends a reminder 24–48 hours before a subscription ends, with a “Renew” button.
- Removes members whose subscription has ended.
To remove a member without a permanent ban, call banChatMember and then unbanChatMember with only_if_banned: true. The member is kicked out but can rejoin later with a new paid link.
Edge cases worth handling
- Paid but the callback was late. Query the STK status for pending payments before telling anyone it failed.
- Paid twice. Extend the subscription instead of ignoring the second payment.
- Member left and wants back in. Issue a fresh link if their subscription is still active.
- Bot lost admin rights. Alert the owner immediately. Nothing works without them.
- Different phone numbers. Members often pay from a family member’s phone. Match payments on the subscription record, not the phone number.
An admin view
Owners need to see active members, revenue, upcoming renewals and failed payments. A simple web dashboard, or a few admin-only bot commands like /stats, saves hours of guesswork.
A note on Telegram Payments
Telegram has its own payments feature with supported providers and Telegram Stars for digital goods. For Kenyan audiences paying by M-Pesa, an STK Push from your own server is usually the most familiar experience. Check Telegram’s current terms for selling digital goods and access in your situation.
Compliance
Be clear about what members get, how renewals work and how to cancel. If you run a trading signals group, add a clear risk disclaimer. You are responsible for the content you sell.
Want a paid-access bot built for your community? See our Telegram and automation service or request a quote.