ptgb
A complete Telegram Bot API client for Dart

Invite Links & Join Requests

Part of the Examples. Invite links that require bot approval to join: createChatInviteLink and chatJoinRequest updates.

Source: example/13_invite_links_and_join_requests.dart

// ignore_for_file: file_names
// (numbered intentionally for reading/run order -- see README.md)

// ============================================================================
// 13 — INVITE LINKS AND JOIN REQUESTS
// ============================================================================
//
// A common but confusing feature: invite links that require the bot's
// approval before someone can actually join. This is different from a
// plain invite link, which lets anyone in immediately.
//
// The flow has three parts:
//   1. Create an invite link with `createsJoinRequest: true`.
//   2. When someone taps it, Telegram sends your bot a `chat_join_request`
//      update instead of letting them straight in.
//   3. Your bot calls `approveChatJoinRequest` or `declineChatJoinRequest`.
//
// Your bot needs to be an admin of the chat with the "invite users" right
// for any of this to work.
//
// HOW TO RUN:
//   1. Create a file named `.env` next to this script containing:
//        TOKEN=123456:ABC-your-token-here
//   2. Add this bot as an admin to a group/channel.
//   3. dart run example/13_invite_links_and_join_requests.dart
//   4. Send /invite to the bot in a private chat to get a join-request link,
//      then try joining the group through it from a different account.
// ============================================================================

import 'dart:developer';

import 'package:ptgb/ptgb.dart';

Future<void> main() async {
  final bot = Bot();

  // Replace with the numeric ID of the group/channel you're testing with —
  // `getChat` or a bot like @userinfobot can help you find it.
  const targetChatId = -1001234567890;

  await for (final update in bot.poll()) {
    // Part 2: someone tapped a join-request link. `chatJoinRequest` is the
    // raw JSON payload Telegram sends — it includes `from` (the requester)
    // and `chat` (which chat they're trying to join).
    final joinRequest = update.chatJoinRequest;
    if (joinRequest != null) {
      // `Update.userId`/`chatId`/`username` already resolve through
      // `chatJoinRequest`'s `from`/`chat` fields, so no need to index the
      // raw JSON by hand.
      final userId = update.userId!;
      final chatId = update.chatId!;
      final username = update.username;

      // A real bot might check an allowlist, a captcha answer, an account
      // age, etc. here before deciding. This demo just approves everyone
      // and logs it.
      await bot.approveChatJoinRequest(chatId, userId);
      log('Approved join request from ${username ?? userId}');

      // To reject instead:
      //   await bot.declineChatJoinRequest(chatId, userId);
      continue;
    }

    final text = update.text;
    final chatId = update.chatId;
    if (text == null || chatId == null) continue;

    if (text == '/invite') {
      // Part 1: create a link that funnels joiners through your bot for
      // approval instead of adding them immediately.
      final link = await bot.createChatInviteLink(
        targetChatId,
        name: 'Approved by bot',
        createsJoinRequest: true,
      );
      await bot.sendMessage(
        chatId,
        'Share this link — anyone who uses it will need my approval to join:\n'
        '${link['invite_link']}',
      );
    }
  }
}

Run it from the package root:

dart run example/13_invite_links_and_join_requests.dart