> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authforge.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Telegram Bot

> Implement Telegram user-based licensing with AuthForge using HWID override.

This pattern lets anyone message your bot, but only licensed users get full responses.

## Architecture

1. User sends a message to your bot.
2. If not licensed, bot asks for a license key.
3. User submits key in DM/private chat.
4. Bot validates key with AuthForge and sets `hwidOverride = tg:<telegram_user_id>`.
5. If valid, store "licensed" status for that Telegram user.

## Why this works

* AuthForge treats HWID as an identity string.
* `tg:<user_id>` is stable per Telegram account.
* Seat controls (`maxHwidSlots`) and reset flows still work.

Use `user_id`, not `username` (usernames can change).

Use `heartbeatMode: "LOCAL"` (or `heartbeat_mode="LOCAL"` in Python) for the bot process. **Server** heartbeat mode targets software running on the licensee’s device; a Telegram bot only performs validation on your infrastructure, so local session checks after `login` are enough.

For **every scheduled run or every message**, use **`validateLicense`** / **`validate_license`** (same `/auth/validate` + Ed25519 verification as `login`) so you **avoid heartbeat timers** and **never need `logout()`** just to stop background intervals. Keep `login` for processes that intentionally hold one long-lived session.

## Node example (Telegraf-style pseudocode)

```javascript theme={null}
import { AuthForgeClient } from "@authforgecc/sdk";

async function validateTelegramKey(telegramUserId, licenseKey) {
  const client = new AuthForgeClient({
    appId: process.env.AUTHFORGE_APP_ID,
    appSecret: process.env.AUTHFORGE_APP_SECRET,
    publicKey: process.env.AUTHFORGE_PUBLIC_KEY,
    heartbeatMode: "LOCAL",
    hwidOverride: `tg:${telegramUserId}`,
  });

  const result = await client.validateLicense(licenseKey);
  return result.valid ? result : { valid: false, code: result.code };
}
```

## Python example

```python theme={null}
from authforge import AuthForgeClient

def validate_telegram_key(user_id: int, license_key: str) -> dict:
    client = AuthForgeClient(
        app_id=APP_ID,
        app_secret=APP_SECRET,
        public_key=PUBLIC_KEY,
        heartbeat_mode="LOCAL",
        hwid_override=f"tg:{user_id}",
    )
    return client.validate_license(license_key)
```

## Recommended bot behavior

* Keep key entry in private chat.
* Rate limit invalid attempts per user and per IP.
* Return clear error text for `invalid_key`, `expired`, `revoked`, `hwid_mismatch`.
* Provide a support command to request reset help when users switch accounts.

## Related

* [HWID override](/features/hwid-override)
* [HWID Override Guide](/guides/hwid-override)
* [License API](/api/licenses)
