1. SYSTEM OVERVIEW
1.1 General Description
The Telegram Subscription Manager Bot is a comprehensive, production-ready solution for managing paid subscriptions to private Telegram channels and groups using cryptocurrency payments. The system automates the entire subscription lifecycle: from trial periods and payment processing to access management and renewal reminders.
This bot integrates seamlessly with the TON (The Open Network) blockchain to process USDT (Tether) payments, automatically verifies transactions, grants or revokes channel and group access based on subscription status, and provides both Telegram-based and web-based administration interfaces.
1.2 General Architecture
- Backend: Node.js runtime with Express.js (v5.2.1) for web API endpoints and Telegraf (v4.16.3) for Telegram Bot API interactions
- Database: PostgreSQL (via pg v8.16.3) for persistent storage, with automatic fallback to JSON file storage if database is unavailable
- Payments: TON Center API (v2) integration for real-time USDT transaction verification on the TON blockchain
- Deployment: Compatible with Render, Vercel, Railway, Heroku, or any VPS hosting Node.js applications
- Admin Interface: Modern web dashboard (vanilla JavaScript) accessible via
/adminroute, secured with session-based authentication - Multi-Channel & Group Support: Manages multiple private Telegram channels and groups simultaneously with individual access control
1.3 Core Features
- Automated Payment Processing: Generates unique payment links, verifies blockchain transactions, and automatically grants access upon payment confirmation
- Trial Period Management: Configurable free trial periods for new users added to channels or groups
- Subscription Renewals: Automatic handling of subscription renewals with expiration date extension
- Grace Periods: Temporary access extensions for users who need extra time to pay
- Whitelisting: Permanent free access for moderators, teachers, or special users
- Exchange Rate Management: Automatic or manual RUB/USDT exchange rate updates
- Background Automation: Scheduled tasks for payment verification (every 5 minutes) and subscription expiration checks (every hour)
- Comprehensive Admin Tools: Both Telegram commands and web dashboard for complete bot management
1.4 Main Use Cases
- Content Creator: Monetize private Telegram channels and groups with premium content, courses, or exclusive materials
- Paid Community: Manage subscription-based Telegram communities with monthly or custom-duration subscriptions
- Educational Service: Provide access to educational resources, courses, or tutoring via private channels and groups
- B2B SaaS: Deploy multiple instances for different clients or resell as a white-label solution
- Membership Platform: Create membership tiers with different subscription durations and pricing
2. DETAILED TECHNICAL ARCHITECTURE
2.1 File Structure
telegram-subscription-bot/
├── index.js # Main entry point (2000+ lines)
│ ├── Express configuration (web server)
│ ├── Telegraf configuration (Telegram bot)
│ ├── User session management
│ ├── Telegram command handlers
│ ├── Periodic payment verification system
│ ├── Subscription and expiration management
│ ├── REST API for admin dashboard
│ └── Admin authentication routes
│
├── services/
│ ├── tonService.js # TON/USDT payment management service
│ │ ├── Telegram Wallet payment link generation
│ │ ├── Transaction verification via TON Center API
│ │ ├── Pending payment management
│ │ ├── RUB/USDT conversion with auto exchange rate
│ │ └── Subscription renewal processing
│ │
│ ├── channelService.js # Telegram channel and group management service
│ │ ├── Grant/revoke access to private channels and groups
│ │ ├── Invitation link creation
│ │ ├── Member status verification
│ │ └── Ban management
│ │
│ └── database.js # PostgreSQL database service
│ ├── Connection with connection pool
│ ├── Auto-detect Supabase pooler (IPv4/IPv6)
│ ├── Tables: subscriptions, grace_periods, user_channels,
│ │ whitelisted_users, trial_access, payments, settings
│ └── Fallback to file storage if DB unavailable
│
├── public/admin/ # Web administration interface
│ ├── index.html # Main dashboard page
│ ├── app.js # Frontend JavaScript logic
│ └── styles.css # CSS styles
│
├── data/ # Persistent storage (if no DB)
│ ├── state.json # Subscriptions, trials, whitelist state
│ └── settings.json # Bot settings
│
└── Configuration files
├── package.json # Node.js dependencies
├── .env # Environment variables (not versioned)
└── env.example # Environment variables template
2.2 Technology Stack
- Runtime: Node.js (version 14+)
- Bot Framework: Telegraf v4.16.3
- Web Framework: Express v5.2.1
- Database: PostgreSQL (via pg v8.16.3)
- HTTP Client: Axios v1.13.2
- Sessions: express-session v1.18.2
- Security: bcryptjs v3.0.3
- Configuration: dotenv v17.2.3
2.3 Main Data Flows
Flow 1: New User Added to Channel or Group
- User added to channel or group → Telegram event "chat_member" or "new_chat_members"
- Bot detects addition →
handleUserAddedToManagedChat() - Bot records user's initial channels and groups →
userChannels Map - Bot starts trial period →
trialAccess Map(configurable duration, default 2 days) - Bot sends welcome message with "Subscribe" button
- Bot saves state →
saveStateSoon()(debounced)
Flow 2: Payment Process
- User clicks "Subscribe" → Action callback "subscribe"
- Bot generates payment link →
tonService.generatePaymentLink() - Creates unique comment:
"subscription_{userId}{timestamp}" - Calculates USDT amount from RUB (if configured)
- Generates Telegram Wallet link:
"https://t.me/wallet?startapp=transfer_..." - Stores pending payment →
pendingPayments Map - User pays via Telegram Wallet → Transaction on TON blockchain
- Bot verifies payment (every 5 min or manually)
- Calls TON Center API →
getTransactions() - Searches for transaction with matching comment
- Verifies amount (90% tolerance)
- If payment found →
processPayment() - Calculates expiration date (adds to end of existing subscription if renewal)
- Stores subscription →
userSubscriptions Map+ DB if available - Grant access →
channelService.grantAccess()for each initial channel - Sends confirmation notification
- Cleans up pending payment
Flow 3: Periodic Expiration Verification
- Interval every hour →
setInterval(..., 60 * 60 * 1000) - For each subscription:
- Checks if expired (
expiresAt < Date.now()) - Checks grace period (
gracePeriods Map) - Checks whitelist (
whitelistedUsers Set) - If expired AND no grace AND not whitelisted:
- → Sends expiration notification
- → Revoke access →
channelService.revokeAccess() - → Removes from
userSubscriptions
- Checks if expired (
- For each trial:
- Checks if expired
- If < 24h remaining AND not yet reminded → Sends reminder
- If expired → Revoke access + Remove trial
- For each active subscription:
- Checks if X days before expiration (
renewalReminderDays) - If yes AND not yet notified → Sends renewal reminder
- Checks if X days before expiration (
3. DETAILED FEATURES
3.1 User Features (via Telegram)
3.1.1 /start Command
Trigger: User sends /start command or clicks the "Start" button in Telegram
Functionality:
- Saves user profile information (username, firstName, lastName) to
userProfilesMap for future reference - Displays a personalized welcome message with subscription information
- If user has an active subscription:
- Shows subscription expiration date
- Displays "Status" and "Renew" buttons for quick access
- Indicates remaining days until expiration
- If no active subscription:
- Shows "🔔 Subscribe" button to initiate payment process
- Displays trial period information if applicable
Implementation: Handler located in index.js at bot.start() callback
Example Usage:
User: /start
Bot: Welcome! Your subscription expires on 2024-02-15.
[Status] [Renew]
3.1.2 Subscribe Button (Action Callback)
Trigger: User clicks the inline "🔔 Subscribe" button
Functionality:
- Calls
tonService.generatePaymentLink(userId)to create a unique payment reference - Generates a unique payment comment in format:
subscription_{userId}_{timestamp} - Calculates USDT amount from RUB using current exchange rate
- Creates a Telegram Wallet deep link:
https://t.me/wallet?startapp=transfer_{walletAddress}_{amount}_{comment} - Stores pending payment information in
pendingPaymentsMap - Displays comprehensive payment instructions including:
- TON wallet address
- Amount in USDT (with 6 decimal precision)
- Amount in RUB (if configured)
- Unique payment comment that must be included in transaction
- Direct "Pay with Telegram Wallet" button (opens Telegram Wallet app)
- "🔄 Check Payment" button for manual verification
Implementation: Handler located in index.js at bot.action('subscribe') callback
Payment Comment Format: subscription_123456789_1704067200000 (userId + timestamp)
3.1.3 Payment Verification
Trigger: User clicks "🔄 Check Payment" button or sends /check_payment command
Functionality:
- Immediately calls
tonService.checkPayment(userId)to verify payment on blockchain - Polls TON Center API's
getTransactionsendpoint - Searches for transactions matching:
- Timestamp after payment request was created
- Comment containing
subscription_{userId} - Amount within 90% tolerance of expected amount
- Destination address matching configured wallet
- If payment found:
- Calls
tonService.processPayment(userId, currentSubscription) - Calculates new expiration date (extends existing subscription if renewal)
- Saves subscription to
userSubscriptionsMap and database - Grants access to all user's initial channels via
channelService.grantAccess() - Sends confirmation notification with expiration date
- Clears pending payment entry
- Calls
- If payment not found: Displays "Payment not yet detected. Please wait a few minutes and try again."
Implementation: Handler located in index.js at bot.action('check_payment') and bot.command('check_payment')
Automatic Verification: Payments are also checked automatically every 5 minutes via background interval
Important: Telegram Wallet Availability
This service integrates with Telegram Wallet for payment processing. Please ensure that Telegram Wallet is available in your country. However, you have full flexibility: You can receive payments to any platform or wallet you prefer, and your subscribers can send payments from any compatible payment method—as long as they follow the bot's instructions and use the correct payment address.
3.1.4 /status Command
Trigger: User sends /status command
Functionality:
- Retrieves user's subscription status from
userSubscriptionsMap - Checks if subscription is active (expiration date in future)
- Displays comprehensive status information:
- Subscription status: "Active" or "Expired"
- Expiration date and time (formatted)
- Remaining days until expiration (if active)
- Grace period information (if active)
- Whitelist status (if applicable)
- If no subscription exists: Shows "No active subscription" message
Implementation: Handler located in index.js at bot.command('status') callback
Example Output:
📊 Subscription Status
✅ Status: Active
📅 Expires: February 15, 2024 at 10:30 AM
⏰ Remaining: 12 days
Your subscription is active and you have access to all channels.
3.2 Administrator Features (via Telegram)
Access Control: All admin commands require the user's Telegram ID to match ADMIN_ID environment variable. Commands are rejected with an error message if unauthorized.
3.2.1 /settings Command
Trigger: Admin sends /settings command
Functionality:
- Displays complete bot configuration and statistics
- Shows payment configuration:
- Subscription amount in RUB
- Subscription amount in USDT (calculated)
- Current USDT to RUB exchange rate
- Exchange rate auto-update status
- Shows subscription settings:
- Subscription duration in days
- Trial period duration
- Renewal reminder days (days before expiration to send reminder)
- Lists all configured channels and groups:
- Channel and group IDs
- Channel and group labels (if configured)
- Total number of channels and groups
- Displays database status:
- Connection status (Connected / Not Connected)
- Storage method (Database / File)
- Shows real-time statistics:
- Active subscriptions count
- Total users count
- Whitelisted users count
- Total revenue (if database available)
Implementation: Handler located in index.js at bot.command('settings') callback
Example Output:
⚙️ Bot Settings
💰 Payment Configuration:
• Amount: 90.00 RUB (1.00 USDT)
• Exchange Rate: 1 USDT = 90.00 RUB
• Auto Update: Disabled
⏱️ Subscription Settings:
• Duration: 30 days
• Trial Period: 2 days
• Renewal Reminder: 5 days before expiration
📢 Channels:
• Configured: 3 channel(s)
• CHAT 1 english (-1003520607330)
• CHAT 2 english (-1003620447473)
• CHAT 3 english (-1003565861542)
🗄️ Database:
• Status: ✅ Connected
📊 Statistics:
• Active subscriptions: 15
• Total users: 42
• Whitelisted users: 3
• Total revenue: 1350.00 USDT
✅ All systems operational!
3.2.2 Configuration Commands
All configuration commands save changes immediately to the database (if available) or settings file. No bot restart is required.
/set_amount <amount_in_rub>
Description: Changes the subscription amount in Russian Rubles (RUB)
Usage: /set_amount 100
Parameters:
amount_in_rub: Subscription amount in RUB (minimum 0.01, must be a valid number)
Functionality:
- Validates the amount (must be positive number)
- Updates
botSettings.subscriptionAmountRub - Recalculates USDT amount based on current exchange rate
- Saves to database/file immediately
- Confirms change with success message
Examples:
/set_amount 90- Set subscription to 90 RUB/set_amount 150.5- Set subscription to 150.50 RUB
/set_duration <days>
Description: Changes the subscription duration in days
Usage: /set_duration 30
Parameters:
days: Number of days for subscription (minimum 1, must be integer)
Functionality:
- Validates the duration (must be positive integer)
- Updates
botSettings.subscriptionDurationDays - Saves to database/file immediately
- Confirms change with success message
Examples:
/set_duration 30- Set to 30 days (monthly)/set_duration 7- Set to 7 days (weekly)/set_duration 90- Set to 90 days (quarterly)
/set_trial <days>
Description: Changes the free trial period duration in days
Usage: /set_trial 2
Parameters:
days: Number of trial days (minimum 0 to disable, must be integer)
Functionality:
- Validates the trial duration (must be non-negative integer)
- Updates
botSettings.trialDaysand recalculatesTRIAL_MS - Saves to database/file immediately
- Confirms change with success message
Examples:
/set_trial 2- Set to 2 days trial/set_trial 7- Set to 7 days trial/set_trial 0- Disable trial period
/set_reminder <days>
Description: Changes when users receive renewal reminders before subscription expiration
Usage: /set_reminder 5
Parameters:
days: Number of days before expiration to send reminder (minimum 0 to disable, must be integer)
Functionality:
- Validates the reminder days (must be non-negative integer)
- Updates
botSettings.renewalReminderDaysandRENEWAL_REMINDER_DAYS - Saves to database/file immediately
- Confirms change with success message
Examples:
/set_reminder 5- Remind 5 days before expiration/set_reminder 7- Remind 7 days before expiration/set_reminder 0- Disable renewal reminders
3.2.3 User Management Commands
/whitelist [user_id]
Description: Adds a user to the whitelist, granting permanent free access to all channels and groups
Usage:
/whitelist 123456789- Whitelist specific user by ID- Reply to user's message with
/whitelist- Whitelist the replied user
Parameters:
user_id: Telegram user ID (optional if replying to message)
Functionality:
- Adds user ID to
whitelistedUsersSet - Saves to database/file immediately
- User gains permanent access without payment requirement
- User will not be removed even if subscription expires
- Useful for moderators, teachers, or special users
- Confirms action with success message
Examples:
/whitelist 123456789- Whitelist user with ID 123456789- Reply to message:
/whitelist- Whitelist the user who sent the message
/unwhitelist [user_id]
Description: Removes a user from the whitelist, requiring them to pay for access
Usage:
/unwhitelist 123456789- Remove specific user by ID- Reply to user's message with
/unwhitelist- Remove the replied user
Parameters:
user_id: Telegram user ID (optional if replying to message)
Functionality:
- Removes user ID from
whitelistedUsersSet - Saves to database/file immediately
- User will need to pay to maintain access
- User's subscription will be checked normally during expiration checks
- Confirms action with success message
/grace <user_id> <days>
Description: Adds a temporary grace period for a user, preventing removal even if subscription expires
Usage: /grace 123456789 3
Parameters:
user_id: Telegram user IDdays: Number of days for grace period (must be positive integer)
Functionality:
- Calculates grace period expiration timestamp
- Adds entry to
gracePeriodsMap - Saves to database/file immediately
- User will not be removed during grace period, even if subscription expired
- Useful when user notifies admin they will pay late
- Confirms action with success message showing expiration date
Example: /grace 123456789 3 - Give user 3 days grace period
/grace_user <days>
Description: Adds a grace period for a user (convenient when replying to their message)
Usage: Reply to user's message with /grace_user 5
Parameters:
days: Number of days for grace period (must be positive integer)
Functionality:
- Extracts user ID from the replied message
- Same functionality as
/gracecommand - More convenient when managing users in a chat
Example:
- User sends a message in chat
- Admin replies:
/grace_user 5 - User gets 5-day grace period automatically
3.3 Automatic Features (Background Processes)
These features run automatically in the background without user intervention, ensuring the bot maintains subscription states, verifies payments, and manages access continuously.
3.3.1 Payment Verification (Every 5 Minutes)
Interval: setInterval(..., 5 * 60 * 1000) - Runs every 5 minutes
Process:
- Retrieves all user IDs with pending payments from
tonService.getPendingUserIds() - For each user ID:
- Calls
tonService.checkPayment(userId)to verify payment on blockchain - If payment found:
- Processes payment via
tonService.processPayment(userId, currentSubscription) - Calculates new expiration date (extends if renewal)
- Saves subscription to database and in-memory Map
- Grants access to all user's initial channels
- Sends confirmation notification to user
- Clears pending payment entry
- Records payment in payments table (if database available)
- Processes payment via
- Calls
Implementation: Located in index.js as a setInterval callback
Error Handling: All errors are caught and logged, preventing the interval from stopping
Performance: Only checks users with pending payments, minimizing API calls to TON Center
3.3.2 Subscription and Trial Expiration Verification (Every Hour)
Interval: setInterval(..., 60 * 60 * 1000) - Runs every hour
Process:
- Subscription Expiration Check:
- Iterates through all entries in
userSubscriptionsMap - For each subscription:
- Checks if
expiresAt < Date.now()(expired) - Checks if user is in grace period (
gracePeriodsMap) - Checks if user is whitelisted (
whitelistedUsersSet) - If expired AND no grace period AND not whitelisted:
- Sends expiration notification to user
- Revokes access from all user's channels via
channelService.revokeAccess() - Removes subscription from
userSubscriptionsMap - Updates database (if available)
- Checks if
- Iterates through all entries in
- Trial Expiration Check:
- Iterates through all entries in
trialAccessMap - For each trial:
- Checks if
expiresAtMs < Date.now()(expired) - If less than 24 hours remaining AND not yet reminded:
- Sends 24-hour reminder notification
- Sets
reminded24h: trueflag
- If expired:
- Sends expiration notification
- Revokes access from all user's channels
- Removes trial from
trialAccessMap - Updates database (if available)
- Checks if
- Iterates through all entries in
- Renewal Reminders:
- Iterates through all active subscriptions
- For each subscription:
- Calculates days until expiration
- If days until expiration equals
renewalReminderDaysAND not yet notified:- Checks
renewalNotificationsSentSet to avoid duplicates - Sends renewal reminder notification
- Adds user to
renewalNotificationsSentSet
- Checks
Implementation: Located in index.js as a setInterval callback
Notification Messages:
- Expiration: "Your subscription has expired. Please renew to continue access."
- Trial 24h reminder: "Your trial expires in 24 hours. Subscribe now to continue access."
- Trial expiration: "Your trial period has ended. Subscribe to regain access."
- Renewal reminder: "Your subscription expires in X days. Renew now to avoid interruption."
3.3.3 Exchange Rate Auto-Update (Every 15 Minutes, if Enabled)
Interval: setInterval(..., 15 * 60 * 1000) - Runs every 15 minutes
Condition: Only runs if botSettings.exchangeRateAuto === true
Process:
- Calls
refreshExchangeRateIfEnabled()function - Fetches USD/RUB exchange rate from external API:
- Primary source:
https://api.exchangerate-api.com/v4/latest/USD(free, no API key) - Extracts RUB rate from response:
response.data.rates.RUB - Assumes USDT ≈ USD (standard assumption)
- Primary source:
- Validates the rate:
- Must be a finite positive number
- If invalid, keeps current rate and logs warning
- If valid:
- Updates
botSettings.usdtToRubRate - Sets
botSettings.exchangeRateLastUpdatedMs = Date.now() - Saves to database/file via
saveSettings() - Logs success message with new rate
- Updates
Error Handling: If API call fails, keeps current rate and logs error (does not crash)
Configuration: Can be enabled/disabled via EXCHANGE_RATE_AUTO environment variable or admin settings
3.4 Web Administration Interface
The web admin interface provides a comprehensive dashboard for managing the bot, viewing statistics, and configuring settings through a user-friendly web interface accessible at https://your-domain.com/admin.
3.4.1 Authentication
Login Route: POST /admin/api/auth/login
Request Body:
{
"password": "your_admin_password"
}
Functionality:
- Compares provided password with
ADMIN_PASSWORDenvironment variable - If correct: Creates session via
express-sessionand returns{ success: true } - If incorrect: Returns
{ success: false, error: "Invalid password" } - Session cookie settings:
httpOnly: true- Prevents JavaScript accesssameSite: 'lax'- CSRF protectionmaxAge: 24 * 60 * 60 * 1000- 24 hours expirationsecure: false- Set to true in production with HTTPS
Logout Route: POST /admin/api/auth/logout
Functionality: Destroys session and returns { success: true }
Check Route: GET /admin/api/auth/check
Functionality: Returns { authenticated: true/false } based on session status
Middleware: All admin API routes (except auth routes) use requireAuth() middleware to verify session
3.4.2 Statistics Dashboard
Route: GET /admin/api/stats
Authentication: Required (session-based)
Response:
{
"activeSubscriptions": 15,
"totalRevenue": 1350.00, // in USDT (if database available)
"totalUsers": 42,
"whitelistedUsers": 3
}
Data Sources:
- If database available: Queries
subscriptionsandpaymentstables - If database unavailable: Calculates from in-memory Maps (
userSubscriptions,whitelistedUsers) - Revenue calculation: Sums all amounts from
paymentstable
3.4.3 User Management
Route: GET /admin/api/users
Authentication: Required
Response: Array of user objects with complete information:
[
{
"userId": "123456789",
"username": "john_doe",
"displayName": "John Doe",
"avatarUrl": "/admin/api/avatars/123456789",
"subscriptionStatus": "active", // active | expired | trial | no_subscription
"userType": "paid", // paid | whitelisted | trial | member | admin
"expiresAt": 1704067200000,
"expiresAtFormatted": "2024-01-01 10:00:00",
"channels": [
{
"channelId": "-1003520607330",
"label": "CHAT 1 english"
}
],
"gracePeriod": {
"active": true,
"expiresAt": 1704153600000,
"expiresAtFormatted": "2024-01-02 10:00:00"
}
}
]
Optimizations:
- Profile Lookup Batching: Limits to 10 Telegram API calls per request to avoid rate limiting
- Avatar Lookup Batching: Limits to 10 photo lookups per request
- Profile Caching: Uses
userProfilesMap to cache user information - Avatar Proxy: Serves avatars via
/admin/api/avatars/:userIdto avoid exposing BOT_TOKEN to frontend
Avatar Proxy Route: GET /admin/api/avatars/:userId
Functionality:
- Fetches user profile photos from Telegram API (server-side)
- Streams image data to client
- Prevents BOT_TOKEN exposure to frontend
- Returns 404 if user has no avatar
3.4.4 Settings Management
Get Settings Route: GET /admin/api/settings
Response:
{
"subscriptionAmountRub": 90.0,
"usdtToRubRate": 90.0,
"exchangeRateAuto": false,
"exchangeRateSourceUrl": "https://api.exchangerate-api.com/v4/latest/USD",
"exchangeRateLastUpdatedMs": null,
"subscriptionDurationDays": 30,
"trialDays": 2,
"renewalReminderDays": 5
}
Update Settings Route: POST /admin/api/settings
Request Body: Partial settings object (only include fields to update):
{
"subscriptionAmountRub": 100.0,
"subscriptionDurationDays": 30
}
Validatable Settings:
subscriptionAmountRub: Must be positive number (minimum 0.01)usdtToRubRate: Must be positive number (minimum 0.01)exchangeRateAuto: BooleanexchangeRateSourceUrl: Must be valid URL stringsubscriptionDurationDays: Must be positive integer (minimum 1)trialDays: Must be non-negative integer (minimum 0)renewalReminderDays: Must be non-negative integer (minimum 0)
Functionality:
- Validates all provided settings
- Merges with existing settings
- Saves to database (priority) or file (fallback)
- Updates in-memory
botSettingsobject - Recalculates derived values (e.g.,
TRIAL_MS) - Returns updated settings object
3.4.5 Whitelist Management
Get Whitelist Route: GET /admin/api/whitelist
Response: Array of whitelisted user IDs:
["123456789", "987654321", "555666777"]
Add to Whitelist Route: POST /admin/api/whitelist
Request Body:
{
"userId": "123456789"
}
Functionality:
- Adds user ID to
whitelistedUsersSet - Saves to database/file
- Returns success confirmation
Remove from Whitelist Route: DELETE /admin/api/whitelist/:userId
Functionality:
- Removes user ID from
whitelistedUsersSet - Saves to database/file
- Returns success confirmation
3.4.6 Grace Period Management
Add Grace Period Route: POST /admin/api/users/:userId/grace
Request Body:
{
"days": 3
}
Functionality:
- Calculates grace period expiration timestamp
- Adds entry to
gracePeriodsMap - Saves to database/file
- Returns grace period information with expiration date
3.4.7 Payment History
Route: GET /admin/api/payments
Authentication: Required
Response: Array of payment records (limited to 100 most recent):
[
{
"id": 1,
"userId": "123456789",
"transactionHash": "abc123...",
"amount": 1000000, // in USDT smallest unit
"currency": "USDT",
"paidAt": 1704067200000,
"paidAtFormatted": "2024-01-01 10:00:00",
"createdAt": 1704067200000
}
]
Data Source: Only available if database is connected (queries payments table)
Limitation: Returns maximum 100 most recent payments, ordered by paid_at descending
4. CONFIGURATION AND ENVIRONMENT VARIABLES
All configuration is managed through environment variables, which can be set in a .env file (for local development) or in your hosting platform's environment variable settings (for production). The bot uses the dotenv package to load these variables at startup.
4.1 Required Variables
These variables must be set for the bot to function. Missing required variables will cause the bot to fail at startup.
Telegram Bot Configuration
| Variable | Type | Description | How to Obtain |
|---|---|---|---|
BOT_TOKEN |
string, required | Telegram bot token obtained from @BotFather. This token authenticates your bot with Telegram's API. | 1. Open Telegram and message @BotFather 2. Send /newbot3. Follow instructions to create bot 4. Copy the token provided |
ADMIN_ID |
number, required | Your Telegram User ID. Only this user can execute admin commands. Must be a numeric ID, not username. | 1. Open Telegram and message @userinfobot 2. Send /start3. Bot will reply with your User ID (numeric) |
Telegram Channels and Groups Configuration
| Variable | Type | Description | Format Example |
|---|---|---|---|
CHANNEL_IDS |
string, required | Comma-separated list of private Telegram channel and group IDs that the bot will manage. The bot must be added as an administrator to these channels and groups with "Invite users" and "Ban users" permissions. | -1003520607330,-1003620447473,-1003565861542Note: No spaces between IDs, use commas only |
CHANNEL_LABELS |
string, optional | Human-readable labels for each channel and group, displayed in admin interface and messages. Format: channelId:label,channelId:label |
-1003520607330:Premium Channel 1,-1003620447473:VIP Group 2Note: Labels can contain spaces and special characters |
How to Get Channel and Group IDs:
- Add @userinfobot to your channel or group
- Forward any message from the channel or group to @userinfobot
- The bot will reply with the channel or group ID (starts with -100)
- Alternatively, use @getidsbot or check channel/group info via Telegram API
TON / USDT Payment Configuration
| Variable | Type | Description | Default Value |
|---|---|---|---|
TON_API_URL |
string, required | Base URL for TON Center API v2. This is the API used to verify USDT transactions on the TON blockchain. | https://toncenter.com/api/v2 |
TON_API_KEY |
string, required | API key for TON Center. Required for accessing transaction data. Free tier allows 1 request per second. | - (must be obtained from TON Center) |
TON_WALLET_ADDRESS |
string, required | Your TON wallet address that will receive USDT payments. Must be a valid TON address (starts with UQ, EQ, or kQ). | - (must be your wallet address) |
How to Get TON Center API Key:
- Visit https://toncenter.com
- Sign up for a free account
- Navigate to API section
- Generate an API key
- Copy the key (starts with alphanumeric characters)
How to Get TON Wallet Address:
- Install a TON wallet (e.g., Tonkeeper, TON Wallet)
- Create or import a wallet
- Copy your wallet address (usually displayed in wallet app)
- Ensure the wallet supports USDT on TON network
Subscription Configuration
| Variable | Type | Description | Default Value |
|---|---|---|---|
SUBSCRIPTION_AMOUNT_RUB |
number, required | Subscription price in Russian Rubles (RUB). This amount will be converted to USDT using the exchange rate for actual payment. | 90.0 |
USDT_TO_RUB_RATE |
number, required | Exchange rate: 1 USDT = X RUB. Used to convert RUB subscription amount to USDT for payment. Can be updated automatically if EXCHANGE_RATE_AUTO is enabled. |
90.0 |
EXCHANGE_RATE_AUTO |
boolean, optional | Enable automatic exchange rate updates. If true, the bot will fetch USD/RUB rate from external API every 15 minutes and update USDT_TO_RUB_RATE automatically. |
false |
EXCHANGE_RATE_SOURCE_URL |
string, optional | URL for exchange rate API. Default uses exchangerate-api.com (free, no API key). Can be changed to use different exchange rate providers. | https://api.exchangerate-api.com/v4/latest/USD |
SUBSCRIPTION_DURATION_DAYS |
number, required | Duration of subscription in days. When a user pays, their subscription will be active for this many days. Can be changed via admin commands without restart. | 30 |
TRIAL_DAYS |
number, required | Free trial period duration in days. When a user is added to a channel or group, they automatically get this many days of free access. Set to 0 to disable trials. |
2 |
RENEWAL_REMINDER_DAYS |
number, required | Number of days before subscription expiration to send renewal reminder notification. Set to 0 to disable reminders. |
5 |
Database Configuration (Optional but Recommended)
Note: Database is optional. If not configured, the bot will use JSON file storage in the data/ directory. However, database is strongly recommended for production use as it provides better reliability and data persistence.
| Variable | Type | Description | Default Value |
|---|---|---|---|
DB_HOST |
string, optional | PostgreSQL database hostname. For Supabase, this is usually db.xxxxx.supabase.co. For local development, use localhost. |
localhost |
DB_PORT |
number, optional | PostgreSQL database port. Standard PostgreSQL port is 5432. For Supabase pooler, use 6543. | 5432 |
DB_NAME |
string, optional | Name of the PostgreSQL database. The bot will create all necessary tables automatically on first connection. | vikkybot |
DB_USER |
string, optional | PostgreSQL database username. For Supabase, this is usually postgres. |
postgres |
DB_PASSWORD |
string, optional | PostgreSQL database password. Keep this secure and never commit to version control. | - |
DB_SSL |
boolean, optional | Enable SSL/TLS for database connection. Required for most cloud database providers (Supabase, Render, etc.). Set to true for production. |
false |
DB_USE_POOLER |
string, optional | Use Supabase connection pooler. Options: auto (auto-detect), true (force pooler), false (direct connection). Pooler uses port 6543 and supports IPv4, which works better on Render and similar platforms. |
auto |
DB_FORCE_IPV4 |
boolean, optional | Force IPv4 for database connections. Recommended for Render and platforms that may have IPv6 connectivity issues. Helps avoid ENETUNREACH errors. | true |
DB_CONNECT_TIMEOUT_MS |
number, optional | Database connection timeout in milliseconds. Increase this value if you experience timeout errors on cold starts (e.g., Supabase on Render). | 10000 (10 seconds) |
Admin Dashboard Configuration
| Variable | Type | Description | Default Value |
|---|---|---|---|
ADMIN_PASSWORD |
string, required | Password for accessing the web admin dashboard at /admin. Use a strong, unique password in production. ⚠️ CHANGE THIS IN PRODUCTION! |
admin123 ⚠️ MUST CHANGE |
SESSION_SECRET |
string, required | Secret key for signing session cookies. Should be a long, random string. Used by express-session to prevent session tampering. Generate a secure random string (64+ characters recommended). | - (must be set) |
How to Generate SESSION_SECRET:
- Use Node.js:
require('crypto').randomBytes(64).toString('hex') - Use online generator: Any secure random string generator
- Use command line:
openssl rand -hex 64
4.2 Complete .env File Example
Below is a complete example of a .env file with all configuration options. Copy this template and replace the placeholder values with your actual credentials.
# ============================================
# Telegram Bot Configuration
# ============================================
# Get BOT_TOKEN from @BotFather on Telegram
BOT_TOKEN=7998967333:AAEalbcIsUxISHxRTdwPHmS_2xU3oweJHe8
# Get ADMIN_ID from @userinfobot on Telegram
ADMIN_ID=348924425
# ============================================
# Telegram Channels and Groups Configuration
# ============================================
# Multiple channels and groups (comma-separated, no spaces)
# Get channel/group IDs by forwarding a message from channel or group to @userinfobot
CHANNEL_IDS=-1003520607330,-1003620447473,-1003565861542
# Channel and group labels for display (format: channelId:label,channelId:label)
# Optional: Makes channels and groups easier to identify in admin interface
CHANNEL_LABELS=-1003520607330:Premium Channel 1,-1003620447473:VIP Group 2,-1003565861542:Exclusive Channel 3
# ============================================
# USDT Payment Configuration (USDT on TON network)
# ============================================
# TON Center API base URL (usually don't change this)
TON_API_URL=https://toncenter.com/api/v2
# Get TON_API_KEY from https://toncenter.com
TON_API_KEY=5fa0f64bed5747f92b5b254fe08dca10c5f923daf57bf458e125dec993a8a7a3
# Your TON wallet address that will receive payments
# Get this from your TON wallet app (Tonkeeper, TON Wallet, etc.)
TON_WALLET_ADDRESS=UQD3_0o0m3ep4Gx63IubK2b0Xz3XoAKoWkkI20ws8Cz465fi
# ============================================
# Subscription Pricing Configuration
# ============================================
# Subscription price in Russian Rubles (RUB)
# This will be converted to USDT using the exchange rate below
SUBSCRIPTION_AMOUNT_RUB=90.0
# Exchange rate: 1 USDT = X RUB
# Update this manually or enable auto-update below
USDT_TO_RUB_RATE=90.0
# Enable automatic exchange rate updates (true/false)
# If true, fetches rate from external API every 15 minutes
EXCHANGE_RATE_AUTO=false
# Exchange rate API URL (free tier, no API key needed)
EXCHANGE_RATE_SOURCE_URL=https://api.exchangerate-api.com/v4/latest/USD
# ============================================
# Subscription Duration and Trial Configuration
# ============================================
# Subscription duration in days (how long each subscription lasts)
SUBSCRIPTION_DURATION_DAYS=30
# Free trial period in days (set to 0 to disable)
TRIAL_DAYS=2
# Days before expiration to send renewal reminder (set to 0 to disable)
RENEWAL_REMINDER_DAYS=5
# ============================================
# Database Configuration (PostgreSQL)
# Optional: If not set, bot uses JSON file storage
# Strongly recommended for production use
# ============================================
# Database hostname (for Supabase: db.xxxxx.supabase.co)
DB_HOST=db.xxxxx.supabase.co
# Database port (5432 for direct, 6543 for pooler)
DB_PORT=5432
# Database name
DB_NAME=telegram_subscription_bot
# Database username (usually 'postgres' for Supabase)
DB_USER=postgres
# Database password (keep secure!)
DB_PASSWORD=your_db_password_here
# Enable SSL for database connection (required for cloud providers)
DB_SSL=true
# Use Supabase connection pooler (auto/true/false)
# Recommended: 'auto' (auto-detects) or 'true' for Supabase
DB_USE_POOLER=auto
# Force IPv4 for database connections (recommended for Render)
DB_FORCE_IPV4=true
# Connection timeout in milliseconds (increase if experiencing timeouts)
DB_CONNECT_TIMEOUT_MS=10000
# ============================================
# Admin Dashboard Configuration
# ============================================
# Password for web admin dashboard at /admin
# ⚠️ CHANGE THIS TO A STRONG PASSWORD IN PRODUCTION!
ADMIN_PASSWORD=your_secure_password_here_change_this
# Secret for signing session cookies
# Generate with: require('crypto').randomBytes(64).toString('hex')
SESSION_SECRET=your_session_secret_change_this_to_random_64_char_string
# ============================================
# Server Configuration
# ============================================
# Port for Express web server (default: 3000)
PORT=3000
# Node environment (development/production)
NODE_ENV=production
Important Notes:
- Never commit your
.envfile to version control (it should be in.gitignore) - Replace all placeholder values with your actual credentials
- Use strong, unique passwords for
ADMIN_PASSWORDandDB_PASSWORD - Generate a secure random string for
SESSION_SECRET - For production, ensure
NODE_ENV=productionis set
5. EXTERNAL API INTEGRATIONS
The bot integrates with several external APIs to provide its functionality. This section documents each integration, including endpoints used, authentication methods, rate limits, and implementation details.
5.1 Telegram Bot API (via Telegraf)
Official Documentation: https://core.telegram.org/bots/api
Library Used: Telegraf v4.16.3 - A modern framework for building Telegram bots in Node.js
Authentication: Uses BOT_TOKEN from environment variables, automatically handled by Telegraf
API Methods Used:
bot.telegram.sendMessage(chatId, text, options): Send text messages to users or channelsbot.telegram.getChatMember(chatId, userId): Check if a user is a member of a chat/channelbot.telegram.banChatMember(chatId, userId): Ban a user from a chat/channel (used to revoke access)bot.telegram.unbanChatMember(chatId, userId): Unban a user from a chat/channel (used before granting access)bot.telegram.createChatInviteLink(chatId, options): Create an invite link for a private channelbot.telegram.getChat(chatId): Get information about a chat/channelbot.telegram.getChatAdministrators(chatId): Get list of administrators in a chat/channelbot.telegram.getUserProfilePhotos(userId, options): Get user profile photos for avatar displaybot.telegram.getFile(fileId): Get file information and download URL
Rate Limits:
- Maximum 30 messages per second per bot
- Telegraf automatically handles rate limiting and retries
- If rate limit is exceeded, requests are queued and retried automatically
Update Method: The bot uses polling (bot.launch()) to receive updates from Telegram. This means the bot continuously polls Telegram's servers for new messages and events. Alternative: Webhooks (not implemented) would require a public HTTPS endpoint.
Event Handlers:
bot.start(): Handles/startcommandbot.command('commandName'): Handles specific commandsbot.action('callbackData'): Handles inline button callbacksbot.on('chat_member'): Handles user join/leave events in channels and groups
5.2 TON Center API
Official Documentation: https://toncenter.com/api/v2/
Base URL: https://toncenter.com/api/v2
Authentication: API key passed in X-API-Key header with value from TON_API_KEY environment variable
Purpose: Verify USDT transactions on the TON blockchain to confirm payments
Endpoints Used:
GET /getTransactions: Retrieve recent transactions for a wallet address- Parameters:
address: TON wallet address (fromTON_WALLET_ADDRESS)limit: Maximum number of transactions to return (default: 100)to_lt: Transaction logical time to start from (0 for latest)archival: Whether to include archived transactions (false for faster queries)
- Response: Array of transaction objects containing:
transaction_id: Unique transaction identifierin_msg: Incoming message data (contains comment and amount)utime: Unix timestamp of transactionfee: Transaction fee
- Parameters:
Rate Limits:
- Free Tier: 1 request per second
- Paid Tiers: Higher limits available (see TON Center pricing)
- Implementation: The bot respects rate limits by checking payments every 5 minutes (not every second)
Payment Verification Process:
- Retrieve last 100 transactions from wallet using
getTransactions - Filter by timestamp: Only consider transactions after payment request was created
- Filter by comment: Transaction comment must contain
subscription_{userId}pattern - Verify amount: Transaction amount must be ≥ 90% of expected amount (allows for small discrepancies)
- Verify destination: Transaction must be to the configured wallet address
- If all conditions met: Payment is confirmed and subscription is activated
Error Handling:
- Network errors: Retried with exponential backoff
- API errors: Logged and payment check is skipped (will retry on next interval)
- Invalid responses: Validated before processing, errors logged
5.3 Exchange Rate API (Optional)
Service: exchangerate-api.com (free tier, no API key required)
Endpoint: GET https://api.exchangerate-api.com/v4/latest/USD
Purpose: Automatically update USDT to RUB exchange rate
Response Format:
{
"base": "USD",
"date": "2024-01-01",
"rates": {
"RUB": 90.5,
"EUR": 0.92,
...
}
}
Usage:
- Fetches USD/RUB exchange rate from the API
- Assumes USDT ≈ USD (standard assumption in cryptocurrency markets)
- Updates
usdtToRubRatein bot settings - Saves updated rate to database/file
Update Frequency: Every 15 minutes (if EXCHANGE_RATE_AUTO=true)
Fallback Behavior:
- If API call fails: Keeps current configured rate
- If response is invalid: Logs warning and keeps current rate
- If rate is not a positive number: Rejects update and keeps current rate
Alternative Sources: Can be configured to use different exchange rate APIs by changing EXCHANGE_RATE_SOURCE_URL
5.4 Telegram File API
Endpoint: https://api.telegram.org/file/bot{BOT_TOKEN}/{file_path}
Purpose: Proxy for serving user avatars in the admin dashboard
Implementation:
- Admin dashboard route:
GET /admin/api/avatars/:userId - Server-side proxy that:
- Fetches user profile photos from Telegram API (using BOT_TOKEN server-side)
- Downloads the image file
- Streams the image to the client
Security Benefits:
- Prevents
BOT_TOKENexposure to frontend JavaScript - Requires admin authentication (session-based)
- Server-side validation of user IDs
Performance:
- Limits to 10 avatar lookups per request to avoid rate limiting
- Caches profile photos in
userProfilesMap - Returns 404 if user has no avatar
6. DATA MANAGEMENT AND PERSISTENCE
The bot uses a hybrid storage approach: in-memory data structures (Maps and Sets) for fast access during runtime, with automatic persistence to either PostgreSQL database (preferred) or JSON files (fallback). This ensures both performance and data durability.
6.1 In-Memory Data Structures (Maps/Sets)
These data structures are loaded into memory at startup and kept synchronized with persistent storage. They provide O(1) lookup performance for critical operations.
userSubscriptions (Map<userId, subscription>)
Purpose: Fast storage of active user subscriptions
Structure:
{
subscriptionId: "ton_123456_abc123", // Unique subscription identifier
expiresAt: 1234567890000, // Expiration timestamp (milliseconds)
createdAt: 1234567890000, // Creation timestamp (milliseconds)
transactionHash: "abc123...", // TON blockchain transaction hash
isRenewal: false // Whether this is a renewal or new subscription
}
Usage:
- Quick lookup of subscription status for any user
- Used in expiration checks to determine if subscription is still active
- Updated when payment is confirmed or subscription expires
Persistence: Saved to data/state.json and PostgreSQL subscriptions table (if database available)
gracePeriods (Map<userId, expiryTimestamp>)
Purpose: Temporary grace periods that prevent user removal even if subscription expires
Structure: userId → expiryTimestamp (milliseconds since epoch)
Example: 123456789 → 1704153600000 (user 123456789 has grace until timestamp 1704153600000)
Usage:
- Checked during expiration verification to prevent removal
- Allows users extra time to pay without losing access
- Automatically removed when grace period expires
Persistence: Saved to data/state.json and PostgreSQL grace_periods table
userChannels (Map<userId, [channelId1, channelId2, ...]>)
Purpose: Tracks which channels and groups a user was initially added to
Structure: userId → array of channel and group IDs
Example: 123456789 → ["-1003520607330", "-1003620447473"]
Usage:
- Stored when user is first added to a managed channel or group
- Used to grant access to all initial channels and groups when payment is confirmed
- Used to revoke access from all channels and groups when subscription expires
Persistence: Saved to data/state.json and PostgreSQL user_channels table
trialAccess (Map<userId, {expiresAtMs, reminded24h}>)
Purpose: Tracks free trial periods for new users
Structure:
{
expiresAtMs: 1234567890000, // Trial expiration timestamp (milliseconds)
reminded24h: false // Whether 24-hour reminder has been sent
}
Usage:
- Created automatically when user is added to a channel or group (if trial enabled)
- Checked hourly for expiration
- Used to send 24-hour reminder before trial ends
- Removed when trial expires or user subscribes
Persistence: Saved to data/state.json and PostgreSQL trial_access table
whitelistedUsers (Set<userId>)
Purpose: Users with permanent free access (moderators, teachers, special users)
Structure: Set of user IDs, e.g., Set([123456, 789012, 555666])
Usage:
- Checked during expiration verification to prevent removal
- Users in whitelist never need to pay
- Can be added/removed via admin commands or web interface
Persistence: Saved to data/state.json and PostgreSQL whitelisted_users table
pendingPayments (Map<userId, {timestamp, amount, comment, checked, currency}>)
Purpose: Tracks payments that are awaiting blockchain confirmation
Structure:
{
timestamp: 1234567890000, // When payment was requested
amount: 1000000, // Amount in USDT smallest unit (6 decimals)
comment: "subscription_123456_1234567890", // Unique payment comment
checked: false, // Whether payment has been verified
currency: "USDT" // Payment currency
}
Usage:
- Created when user clicks "Subscribe" button
- Used by background payment checker to verify transactions
- Removed when payment is confirmed or manually cleared
Persistence: In-memory only (lost on restart, but recreated if user clicks "Check Payment" again)
Location: Stored in services/tonService.js as part of the TON service
6.2 PostgreSQL Database Schema
All tables are automatically created on first database connection if they don't exist. The bot uses the pg library for PostgreSQL interactions with connection pooling.
Table: subscriptions
Purpose: Stores active user subscriptions
CREATE TABLE subscriptions (
user_id BIGINT PRIMARY KEY, -- Telegram user ID (unique per user)
subscription_id TEXT, -- Unique subscription identifier
expires_at BIGINT NOT NULL, -- Expiration timestamp (milliseconds)
created_at BIGINT NOT NULL, -- Creation timestamp (milliseconds)
transaction_hash TEXT, -- TON blockchain transaction hash
is_renewal BOOLEAN DEFAULT FALSE -- Whether this is a renewal
);
CREATE INDEX idx_subscriptions_expires_at ON subscriptions(expires_at);
Indexes: Index on expires_at for fast expiration queries
Table: grace_periods
Purpose: Stores temporary grace periods for users
CREATE TABLE grace_periods (
user_id BIGINT PRIMARY KEY, -- Telegram user ID
expires_at BIGINT NOT NULL -- Grace period expiration timestamp (milliseconds)
);
Table: user_channels
Purpose: Maps users to their initial channels and groups (many-to-many relationship)
CREATE TABLE user_channels (
user_id BIGINT NOT NULL, -- Telegram user ID
channel_id TEXT NOT NULL, -- Telegram channel ID
PRIMARY KEY (user_id, channel_id) -- Composite primary key
);
Note: One user can have multiple channels, one channel can have multiple users
Table: whitelisted_users
Purpose: Stores users with permanent free access
CREATE TABLE whitelisted_users (
user_id BIGINT PRIMARY KEY, -- Telegram user ID
added_at BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()) * 1000 -- When user was whitelisted
);
Table: trial_access
Purpose: Tracks free trial periods for users
CREATE TABLE trial_access (
user_id BIGINT PRIMARY KEY, -- Telegram user ID
expires_at_ms BIGINT NOT NULL, -- Trial expiration timestamp (milliseconds)
reminded_24h BOOLEAN DEFAULT FALSE -- Whether 24-hour reminder was sent
);
Table: payments
Purpose: Historical record of all confirmed payments
CREATE TABLE payments (
id SERIAL PRIMARY KEY, -- Auto-incrementing payment ID
user_id BIGINT NOT NULL, -- Telegram user ID
transaction_hash TEXT NOT NULL, -- TON blockchain transaction hash
amount BIGINT NOT NULL, -- Amount in USDT smallest unit (6 decimals)
currency TEXT DEFAULT 'USDT', -- Payment currency
paid_at BIGINT NOT NULL, -- When payment was made (timestamp, milliseconds)
created_at BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()) * 1000 -- Record creation time
);
CREATE INDEX idx_payments_user_id ON payments(user_id);
CREATE INDEX idx_payments_paid_at ON payments(paid_at);
Indexes: Indexes on user_id and paid_at for fast queries
Usage: Used for revenue calculations and payment history in admin dashboard
Table: settings
Purpose: Stores bot configuration settings as key-value pairs
CREATE TABLE settings (
key TEXT PRIMARY KEY, -- Setting key (e.g., 'bot_settings')
value JSONB NOT NULL, -- Setting value as JSON
updated_at BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()) * 1000 -- Last update timestamp
);
Usage: Stores bot settings with key 'bot_settings' and value as JSON object containing all configuration
JSONB Benefits: Allows efficient querying and indexing of JSON data in PostgreSQL
6.3 File Storage (Fallback if Database Unavailable)
If PostgreSQL database is not configured or unavailable, the bot automatically falls back to JSON file storage in the data/ directory. This ensures the bot continues to function even without a database.
File: data/state.json
Purpose: Stores all user state data (subscriptions, trials, grace periods, channels, whitelist)
Structure:
{
"userSubscriptions": {
"123456": {
"subscriptionId": "ton_123456_abc123",
"expiresAt": 1234567890000,
"createdAt": 1234567890000,
"transactionHash": "abc123...",
"isRenewal": false
}
},
"gracePeriods": {
"123456": 1234567890000
},
"userChannels": {
"123456": ["-1003520607330", "-1003620447473"]
},
"trialAccess": {
"123456": {
"expiresAtMs": 1234567890000,
"reminded24h": false
}
},
"whitelistedUsers": [123456, 789012],
"userProfiles": {
"123456": {
"username": "john_doe",
"firstName": "John",
"lastName": "Doe",
"updatedAt": 1234567890000
}
},
"savedAt": "2024-01-01T00:00:00.000Z"
}
Auto-Creation: File is automatically created if it doesn't exist
Auto-Save: Saved automatically when state changes (with debouncing to prevent excessive writes)
File: data/settings.json
Purpose: Stores bot configuration settings
Structure:
{
"subscriptionAmountRub": 90.0,
"usdtToRubRate": 90.0,
"exchangeRateAuto": false,
"exchangeRateSourceUrl": "https://api.exchangerate-api.com/v4/latest/USD",
"exchangeRateLastUpdatedMs": null,
"subscriptionDurationDays": 30,
"trialDays": 2,
"renewalReminderDays": 5
}
Auto-Creation: File is automatically created with default values if it doesn't exist
Auto-Save: Saved immediately when settings are changed via admin commands or web interface
6.4 Persistence Strategy
The bot uses a smart persistence strategy that prioritizes database storage but gracefully falls back to file storage when needed.
Storage Priority
- Database (Primary): If database is available and connected, all data is saved to PostgreSQL
- File Storage (Fallback): If database is unavailable, data is saved to JSON files in
data/directory
Startup Process
- Attempts to connect to PostgreSQL database (if configured)
- If database connection succeeds:
- Creates tables if they don't exist
- Loads data from database into in-memory Maps/Sets
- If
data/state.jsonexists and is newer than database data, syncs file data to database
- If database connection fails:
- Logs warning message
- Falls back to file storage
- Loads data from
data/state.jsonanddata/settings.json - Bot continues to function normally
Write Operations
- Immediate Writes: Settings changes are saved immediately (both to DB and file if DB unavailable)
- Debounced Writes: State changes use
saveStateSoon()function with 500ms debounce to prevent excessive file writes - Dual Write: When database is available, data is written to both database and file (for redundancy)
Data Synchronization
- On startup: If both database and file exist, database takes priority
- If file is newer than database: File data is synced to database (one-time migration)
- During runtime: Database is always the source of truth if available
Performance Considerations
- In-memory Maps/Sets provide O(1) lookup performance
- Database queries use indexes for fast expiration checks
- File writes are debounced to prevent I/O bottlenecks
- State is only saved when changes occur (not on every read)
7. SECURITY AND PERMISSIONS
7.1 Admin Authentication
Method: Simple password authentication stored in ADMIN_PASSWORD environment variable
Session Management:
- Uses
express-sessionfor session management - Session cookies configured with:
httpOnly: true- Prevents JavaScript access to cookiessameSite: 'lax'- CSRF protectionmaxAge: 24 * 60 * 60 * 1000- 24-hour session expirationsecure: false- Set totruein production with HTTPS
Protected Routes: All routes under /admin/api/* (except /auth/*) use requireAuth() middleware to verify session
⚠️ Recommended Improvement: Use bcrypt to hash passwords (bcryptjs is already installed but not currently used for password hashing)
7.2 Token Security
- BOT_TOKEN: Never exposed to frontend. Avatar proxy route (
/admin/api/avatars/:userId) handles Telegram API calls server-side - TON_API_KEY: Stored only server-side in environment variables, never sent to client
- SESSION_SECRET: Used to sign session cookies, preventing tampering. Must be a strong, random string
- Database Credentials: Stored in environment variables, never logged or exposed
7. Input Validation
- Admin Commands: All admin commands verify
ctx.from.id === ADMIN_IDbefore execution - Settings Parameters: All settings are validated for type, min/max values, and format before saving
- User IDs: Parsed with
parseInt()and validated (checked for NaN, must be positive integers) - API Requests: Request bodies are validated before processing
- SQL Injection Prevention: Uses parameterized queries via
pglibrary
7.4 Error Handling
- Try-Catch Blocks: All async operations are wrapped in try-catch blocks to prevent crashes
- Error Logging: Errors are logged with
console.error()for debugging - Graceful Degradation: If database is unavailable, bot continues with file storage without crashing
- Rate Limiting: Automatically handled by Telegraf for Telegram API calls
- API Error Handling: Network errors and API failures are caught and logged, with retry logic where appropriate
8. DEPLOYMENT AND HOSTING
8.1 Prerequisites
- Node.js 14+ installed
- Telegram account with bot created via @BotFather
- TON Center account with API key
- TON wallet configured
- (Optional) PostgreSQL database (Supabase, Render, etc.)
8.2 Deployment on Render
- Create Render account: https://render.com
- Connect GitHub/GitLab repository
- Create Web Service:
- Name: telegram-subscription-bot (or any name you prefer)
- Environment: Node
- Build Command:
npm install - Start Command:
npm start - Plan: Free (or paid to avoid sleep)
- Configure environment variables: Copy all variables from .env
- Deploy: Render builds and starts automatically
- Health check: Route
/healthfor monitoring
8.3 Deployment on Other Platforms
- Vercel: Compatible (serverless functions)
- Railway: Compatible (direct deployment)
- Heroku: Compatible (Git deployment)
- VPS: Compatible (PM2 recommended for process management)
8.4 Database Configuration (Supabase)
- Create Supabase project: https://supabase.com
- Retrieve credentials: Host, port, database, user, password
- Configure variables:
DB_HOST=db.xxxxx.supabase.coDB_SSL=trueDB_USE_POOLER=auto(recommended to avoid IPv6 issues)
- Tables created automatically: The bot creates tables on first startup
8.5 Monitoring and Logs
- Render Logs: Accessible via Render dashboard
- Health check:
GET /healthreturns{ status: 'ok', timestamp: ... } - Console logs: All important events are logged
9. LIMITATIONS AND CONSIDERATIONS
9.1 Technical Limitations
- Ephemeral file storage: On Render (Free plan), files are lost on restart → Use database in production
- Telegram rate limiting: 30 messages/second max per bot
- TON Center rate limiting: Free plan = 1 req/sec
- Polling vs Webhooks: The bot uses polling (no Telegram webhook configured)
- Payment verification: Delay up to 5 minutes (verification interval)
9.2 Functional Limitations
- Single wallet: All payments go to the same wallet (no multi-wallet support)
- Single amount: No multiple subscription plans (only one configured price)
- No refunds: No automatic refund system
- No invoices: No PDF invoice generation
- No email notifications: Only Telegram notifications
9.3 SaaS Considerations
To transform into a "simple" SaaS where users just enter their info and the bot starts automatically, it would require:
- Automatic Telegram bot creation:
- Use unofficial BotFather API (risky)
- Or guided step-by-step process with verifications
- Automatic channel configuration:
- User must create channels manually
- User must add bot as admin manually
- Cannot be fully automated (Telegram API limitations)
- Automatic TON wallet creation:
- Possible via TON API (complex)
- Or guide user to create wallet
- Automatic deployment:
- Use Render/Vercel API to create services
- Generate GitHub repo with user config
- Deploy automatically
- Multi-tenant architecture:
- Alternative: Single bot managing multiple "tenants"
- Each user has their isolated configuration space
- Resource sharing (less expensive)
9.4 Production Recommendations
- ✅ Use PostgreSQL database (not file storage)
- ✅ Change default
ADMIN_PASSWORD - ✅ Use strong
SESSION_SECRET(64 random characters) - ✅ Enable
EXCHANGE_RATE_AUTOfor up-to-date exchange rates - ✅ Monitor logs for errors
- ✅ Regular database backups
- ⚠️ Consider paid TON Center plan if many users
- ⚠️ Consider paid Render plan to avoid sleep (Free plan goes to sleep after inactivity)
10. TECHNICAL ROADMAP FOR SAAS
10.1 Phase 1: Guided Configuration Assistant (Recommended)
Objective: Web wizard that guides the user step by step
Features:
- Step 1 - Telegram Bot Creation:
- Clear instructions with screenshots
- Form to enter BOT_TOKEN
- Automatic token verification (connection test)
- Step 2 - Channel Configuration:
- Instructions to create channels
- Instructions to add bot as admin
- Form to enter CHANNEL_IDS
- Automatic verification (can bot access channels?)
- Step 3 - TON Configuration:
- Instructions to create TON Center account
- Form to enter TON_API_KEY and TON_WALLET_ADDRESS
- Automatic verification (test API call)
- Step 4 - Subscription Configuration:
- Form for amount, duration, trial period
- Parameter preview
- Step 5 - Deployment:
- Option A: Generate GitHub repo with config
- Option B: Deploy automatically via Render API
- Final instructions
Technical Stack:
- Frontend: React/Next.js for the wizard
- Backend: Express API for verifications and config generation
- Deployment: Render/Vercel API for automatic service creation
10.2 Phase 2: Multi-Tenant Architecture
Objective: Single bot managing multiple users (tenants)
Required Modifications:
- Tenants table in DB:
CREATE TABLE tenants ( id SERIAL PRIMARY KEY, user_id BIGINT, -- Telegram user ID of owner bot_token TEXT, channel_ids TEXT[], ton_api_key TEXT, ton_wallet_address TEXT, settings JSONB, created_at TIMESTAMP ); - Message routing:
- Identify which tenant manages which channel
- Route commands to the correct context
- Data isolation:
- All in-memory Maps become
Map<tenantId, Map<userId, ...>> - Or use DB only (simpler)
- All in-memory Maps become
- Management interface:
- Dashboard to create/manage multiple bots
- Each user can have multiple instances
Advantages:
- Resource sharing (less expensive)
- Single deployment to maintain
- Simpler scaling
Disadvantages:
- More complex to develop
- Risk of confusion if multiple tenants use same channels
- Telegram rate limiting shared between all tenants
10.3 Phase 3: Complete Automation
Objective: User just enters their info, everything happens automatically
Technical Challenges:
- Telegram bot creation:
- Unofficial BotFather API (risky, may be blocked)
- Alternative: Semi-automated process with verifications
- Channel creation:
- Impossible via Telegram API (user must create manually)
- Solution: Very clear instructions + automatic verification
- TON wallet creation:
- Possible via TON API but complex
- Alternative: Guide user or use third-party service
- Automatic deployment:
- ✅ Possible via Render/Vercel API
- Generate GitHub repo automatically
- Create Render service automatically
- Configure environment variables automatically
Technical Stack:
- GitHub API: Create repo, push code
- Render API: Create web service, configure env vars
- TON API: Create wallet (if possible)
- Telegram API: Verify token, verify channel access
11. TESTING AND TROUBLESHOOTING
11.1 Tests to Perform
- Bot creation test: Verify that BOT_TOKEN works
- Channel addition test: Verify that bot can access channels
- Payment test: Perform a real payment and verify detection
- Expiration test: Wait for trial/subscription expiration and verify revoke
- Admin dashboard test: Verify authentication and all routes
- Database test: Verify that data is properly saved
11.2 Common Issues and Solutions
Bot won't start
- Cause: Missing or incorrect environment variables
- Solution: Check .env, check error logs
Payments not detected
- Cause: Incorrect TON_API_KEY, incorrect wallet address, blockchain delay
- Solution: Verify credentials, wait 5 minutes, use "Check Payment"
User not added to channel
- Cause: Bot not admin of channel, incorrect CHANNEL_ID, insufficient permissions
- Solution: Verify that bot is admin with "Invite users" and "Ban users" permissions
DB connection failed
- Cause: Incorrect credentials, IPv6 network issue, timeout
- Solution: Verify credentials, enable
DB_USE_POOLER=autofor Supabase, increaseDB_CONNECT_TIMEOUT_MS
Admin dashboard inaccessible
- Cause: Incorrect password, expired session
- Solution: Verify
ADMIN_PASSWORD, reconnect
12. METRICS AND ANALYTICS
12.1 Available Metrics
- Active subscriptions: Number of users with non-expired subscription
- Total users: Total number of users who have had a subscription
- Whitelisted users: Number of users with permanent free access
- Total revenue: Sum of all payments (if DB available)
- Recent payments: History of the last 100 payments
12.2 Where to Find Metrics
- Admin dashboard: Route
/admin/api/stats - Telegram command:
/settings(displays basic statistics) - Database: Tables
subscriptions,paymentsfor advanced analytics
12.3 Advanced Analytics (to implement)
- Growth charts (new subscribers per day)
- Conversion rate (trials → payments)
- Retention rate (renewals)
- Revenue by period (day/week/month)
13. USER DOCUMENTATION
13.1 End User Guide (for subscribers)
- How to start the bot (
/start) - How to subscribe (Subscribe button)
- How to pay (Telegram Wallet instructions)
- How to verify payment
- How to check status (
/status) - FAQ (payment not detected, expiration, etc.)
13.2 Administrator Guide
- Initial configuration (environment variables)
- Available Telegram commands
- Using the admin dashboard
- User management (whitelist, grace period)
- Modifying settings
- Deployment and maintenance
14. POSSIBLE FUTURE IMPROVEMENTS
14.1 Features
- Multiple subscription plans (monthly, quarterly, annual)
- Promo codes / discounts
- Referral system
- Email notifications in addition to Telegram
- PDF invoice generation
- Multi-currency support (not just RUB/USDT)
- Refund system
- Advanced analytics with charts
- Data export (CSV/JSON)
14.2 Technical Improvements
- Telegram webhooks (instead of polling) for better performance
- Redis cache for sessions and frequent data
- Queue system (Bull/BullMQ) for asynchronous tasks
- Unit and integration tests
- CI/CD pipeline
- Monitoring with Sentry
- Structured logging (Winston)
- Public REST API for third-party integrations
14.3 UX Improvements
- More modern admin interface (React with Material-UI)
- Push notifications for important events
- Integrated support chat
- Interactive documentation
- Video tutorials
15. CONCLUSION
This comprehensive technical documentation provides all the information necessary to understand, maintain, and extend the Telegram TON Subscription Bot system. The system is fully functional in its current state and can be enhanced to become a complete SaaS solution with full automation of configuration and deployment.
Key Takeaways
- Modular and Extensible Architecture: Clean separation of concerns with service-based design (TON service, channel service, database service)
- Multi-Channel & Group Support: Granular management of multiple Telegram channels and groups with individual access control
- Robust Blockchain Payment System: Automated USDT payment verification on TON network with transaction matching and amount tolerance
- Comprehensive Administration Interface: Both Telegram commands and web dashboard for complete bot management
- Flexible Persistence: Database-first approach with automatic fallback to file storage for reliability
- Production-Ready: With minor security adjustments (bcrypt password hashing, HTTPS), the system is ready for production deployment
Recommended Next Steps
- Security Enhancements: Implement bcrypt password hashing for
ADMIN_PASSWORD(bcryptjs is already installed) - Testing: Add unit tests and integration tests for critical functionality (payment verification, subscription management)
- SaaS Wizard: Create a guided configuration wizard for SaaS deployment (web interface for initial setup)
- Multi-Tenant Architecture: If needed, implement multi-tenant support for managing multiple bot instances
- Monitoring and Alerting: Add comprehensive monitoring (Sentry, logging) and alerting for production environments
- Documentation: Create user-facing documentation and video tutorials for end users
Support and Maintenance
This documentation serves as a complete reference for developers working with the codebase. For questions or issues, refer to the relevant sections:
- Configuration Issues: See Section 4 (Configuration and Environment Variables)
- Payment Problems: See Section 5.2 (TON Center API) and Section 11 (Testing & Troubleshooting)
- Deployment Questions: See Section 8 (Deployment and Hosting)
- Command Reference: See Section 3 (Detailed Features) for all user and admin commands
- API Integration: See Section 5 (External API Integrations) for API details
Thank you for using the Telegram TON Subscription Bot! This system provides a solid foundation for managing paid subscriptions to Telegram channels and groups using cryptocurrency payments.