Skip to content

A Cloudflare Worker for forwarding messages to Telegram chats using the Telegram Bot API. This service provides a REST API for sending messages to single or multiple Telegram chats, with support for reusable profile configurations.

Notifications You must be signed in to change notification settings

vutadev/telegram-worker

Repository files navigation

Telegram Worker

A Cloudflare Worker for forwarding messages to Telegram chats using the Telegram Bot API. This service provides a REST API for sending messages to single or multiple Telegram chats, with support for reusable profile configurations.

Features

  • Message Forwarding: Send messages to one or multiple Telegram chats via REST API
  • Profile Management: Store and reuse bot token and chat ID combinations
  • Batch Sending: Send the same message to multiple chats in a single request
  • Flexible Content: Support for plain text and rich formatting (HTML, Markdown)
  • Multi-Status Responses: HTTP 207 for partial batch failures with detailed per-chat results
  • API Authentication: Bearer token authentication to protect all endpoints
  • Security: Bot tokens excluded from all response bodies, constant-time token comparison
  • Database Storage: Cloudflare D1 database for persistent profile storage
  • CORS Support: Cross-origin requests enabled for browser access

Prerequisites

Before you begin, you'll need:

  1. Cloudflare Account: Sign up at cloudflare.com
  2. Telegram Bot: Create a bot via @BotFather and get your bot token
  3. Chat IDs: Obtain the chat IDs where you want to send messages
    • For personal chats: Use your user ID (get it from @userinfobot)
    • For groups: Add your bot to the group and get the group chat ID (negative number)
    • For channels: Add your bot as admin and get the channel ID
  4. Node.js: Version 16 or higher
  5. Wrangler CLI: Cloudflare's CLI tool for Workers (installed via npm)

Installation

  1. Clone the repository (or copy the files to your project):
git clone <repository-url>
cd telegram-worker
  1. Install dependencies:
npm install
  1. Create a D1 database for local development:
wrangler d1 create telegram_worker_db

Take note of the database_id from the output and update wrangler.toml.

  1. Update wrangler.toml with your database ID:
[[d1_databases]]
binding = "DB"
database_name = "telegram_worker_db"
database_id = "your-database-id-here"
  1. Apply the database schema:
wrangler d1 execute telegram_worker_db --local --file=./schema.sql
  1. Set up environment variables for local development:
cp .env.example .dev.vars
# Edit .dev.vars and set API_TOKEN to any test value

Configuration

Authentication Setup

IMPORTANT: All API endpoints (except OPTIONS for CORS) require authentication via Bearer token.

  1. Generate a secure API token:
# Generate a random 32-character token (recommended)
openssl rand -base64 32

# Or use any strong password generator
  1. Set the API token as a Cloudflare secret:
wrangler secret put API_TOKEN
# Enter your token when prompted
  1. Include the token in all API requests:
curl -X POST https://your-worker.workers.dev/send-message \
  -H "Authorization: Bearer your-api-token-here" \
  -H "Content-Type: application/json" \
  -d '{"chatId": "123456789", "botToken": "...", "content": "Hello!"}'

Security Notes:

  • Use a strong, random token (at least 32 characters recommended)
  • Never commit tokens to version control
  • Rotate tokens regularly for security
  • Use different tokens for different environments (dev, staging, production)
  • All authentication failures return the same generic 401 error (no details leaked)

Environment Variables

For local development, copy the example environment file:

cp .env.example .dev.vars

Edit .dev.vars and set the required variables:

  • API_TOKEN - Required for authentication (use any test value locally)
  • TELEGRAM_BOT_TOKEN - Optional default bot token
  • FORWARD_TO_CHAT_ID - Optional default chat ID

Example .dev.vars for local testing:

API_TOKEN=test-token-dev-12345
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz12345678
FORWARD_TO_CHAT_ID=123456789

For production deployment, use Cloudflare Secrets for sensitive values:

# Required
wrangler secret put API_TOKEN

# Optional
wrangler secret put TELEGRAM_BOT_TOKEN

Note: Bot tokens and chat IDs can be provided per-request or stored in profiles. Environment variables are optional defaults.

Database Schema

The worker uses a single profiles table to store reusable bot configurations:

CREATE TABLE profiles (
  id TEXT PRIMARY KEY,
  chat_ids TEXT NOT NULL,  -- JSON array of chat IDs
  bot_token TEXT NOT NULL,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
);

Local Development

Run the worker locally with hot reloading:

npm run dev

This starts a local server at http://localhost:8787 with access to your local D1 database.

API Endpoints

1. Send Message

POST /send-message

Send a message to one or multiple Telegram chats.

Request Body (Direct Mode):

{
  "chatId": "123456789",
  "botToken": "123456:ABC-DEF...",
  "content": "Hello, World!"
}

Request Body (Profile Mode):

{
  "profileId": "my-profile",
  "content": {
    "text": "<b>Alert!</b>",
    "parse_mode": "HTML"
  }
}

Request Body (Batch Mode):

{
  "chatId": ["123456789", "-987654321"],
  "botToken": "123456:ABC-DEF...",
  "content": "Broadcast message"
}

Response (200 OK - All messages sent):

{
  "success": true,
  "data": {
    "results": [
      {
        "chatId": "123456789",
        "success": true,
        "messageId": 42
      }
    ],
    "totalSent": 1,
    "totalFailed": 0
  }
}

Response (207 Multi-Status - Partial failure):

{
  "success": true,
  "data": {
    "results": [
      {
        "chatId": "123456789",
        "success": true,
        "messageId": 42
      },
      {
        "chatId": "-987654321",
        "success": false,
        "error": "Forbidden: bot is not a member of the supergroup chat"
      }
    ],
    "totalSent": 1,
    "totalFailed": 1
  }
}

2. Create Profile

POST /profiles

Create a new reusable profile with bot token and chat IDs.

Request Body:

{
  "id": "production-bot",
  "chatIds": ["123456789", "-987654321"],
  "botToken": "123456:ABC-DEF..."
}

Response (201 Created):

{
  "success": true,
  "data": {
    "id": "production-bot",
    "chat_ids": "[\"123456789\",\"-987654321\"]",
    "created_at": 1699999999999,
    "updated_at": 1699999999999
  }
}

3. Get Profile

GET /profiles/:id

Retrieve a specific profile by ID.

Response (200 OK):

{
  "success": true,
  "data": {
    "id": "production-bot",
    "chat_ids": "[\"123456789\",\"-987654321\"]",
    "created_at": 1699999999999,
    "updated_at": 1699999999999
  }
}

4. List Profiles

GET /profiles?limit=50&offset=0

List all profiles with pagination.

Query Parameters:

  • limit - Maximum number of profiles to return (default: 50, max: 1000)
  • offset - Number of profiles to skip (default: 0)

Response (200 OK):

{
  "success": true,
  "data": [
    {
      "id": "profile-1",
      "chat_ids": "[\"123456789\"]",
      "created_at": 1699999999999,
      "updated_at": 1699999999999
    },
    {
      "id": "profile-2",
      "chat_ids": "[\"111\",\"222\"]",
      "created_at": 1699999999998,
      "updated_at": 1699999999998
    }
  ]
}

5. Update Profile

PUT /profiles/:id

Update an existing profile's chat IDs and/or bot token.

Request Body (at least one field required):

{
  "chatIds": ["111111111", "222222222"],
  "botToken": "123456:NEW-TOKEN"
}

Response (200 OK):

{
  "success": true,
  "data": {
    "id": "production-bot",
    "chat_ids": "[\"111111111\",\"222222222\"]",
    "created_at": 1699999999999,
    "updated_at": 1700000000000
  }
}

6. Delete Profile

DELETE /profiles/:id

Delete a profile permanently.

Response (200 OK):

{
  "success": true,
  "data": {
    "message": "Profile deleted successfully"
  }
}

Usage Examples

Note: All examples below require the Authorization: Bearer <token> header. Replace YOUR_API_TOKEN with your actual API token.

Send a Simple Text Message

curl -X POST https://your-worker.workers.dev/send-message \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chatId": "123456789",
    "botToken": "123456:ABC-DEF...",
    "content": "Hello from Telegram Worker!"
  }'

Send a Formatted Message

curl -X POST https://your-worker.workers.dev/send-message \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chatId": "123456789",
    "botToken": "123456:ABC-DEF...",
    "content": {
      "text": "<b>Alert!</b>\nSomething important happened.",
      "parse_mode": "HTML",
      "disable_notification": false
    }
  }'

Send to Multiple Chats

curl -X POST https://your-worker.workers.dev/send-message \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chatId": ["123456789", "-987654321", "555555555"],
    "botToken": "123456:ABC-DEF...",
    "content": "Broadcast message to all chats"
  }'

Create a Profile

curl -X POST https://your-worker.workers.dev/profiles \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "my-bot",
    "chatIds": ["123456789"],
    "botToken": "123456:ABC-DEF..."
  }'

Send Message Using Profile

curl -X POST https://your-worker.workers.dev/send-message \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "my-bot",
    "content": "Message using stored profile!"
  }'

List All Profiles

curl https://your-worker.workers.dev/profiles?limit=10&offset=0 \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Update a Profile

curl -X PUT https://your-worker.workers.dev/profiles/my-bot \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chatIds": ["111111111", "222222222"]
  }'

Delete a Profile

curl -X DELETE https://your-worker.workers.dev/profiles/my-bot \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Security Best Practices

Bot Token Security

  1. Never commit bot tokens to version control

    • Add .env files to .gitignore
    • Use Cloudflare secrets for production tokens
  2. Store tokens securely

    • Use profiles to store tokens in the D1 database
    • Tokens are never included in API responses
    • Database is only accessible from your worker
  3. Rotate tokens regularly

    • Generate new tokens via @BotFather
    • Update profiles with new tokens
    • Revoke old tokens

API Access Control

The worker uses Bearer token authentication to protect all endpoints.

Authentication Security:

  • All requests require valid API token in Authorization header
  • Constant-time token comparison prevents timing attacks
  • Generic error responses prevent information leakage
  • OPTIONS requests bypass auth to allow CORS preflight

Additional Security Measures (optional):

  1. Rate limiting

    • Use Cloudflare Rate Limiting rules
    • Implement per-profile rate limits
  2. IP whitelisting

    • Restrict access to known IPs via Cloudflare Firewall rules
    • Combine with token auth for defense in depth
  3. Token rotation

    • Rotate API tokens regularly (e.g., every 90 days)
    • Use different tokens per environment
    • Revoke old tokens after rotation

Chat ID Validation

  • Chat IDs are validated as numeric strings
  • Negative numbers indicate groups/channels
  • Positive numbers indicate private chats
  • Invalid IDs will fail with descriptive errors

Error Handling

The API uses standard HTTP status codes:

  • 200 OK - Request successful
  • 201 Created - Profile created successfully
  • 207 Multi-Status - Partial success (some messages sent, some failed)
  • 400 Bad Request - Invalid request body or parameters
  • 401 Unauthorized - Missing or invalid API token
  • 404 Not Found - Profile or route not found
  • 405 Method Not Allowed - Invalid HTTP method for route
  • 500 Internal Server Error - Server or Telegram API error

All error responses include a descriptive message:

{
  "success": false,
  "error": "Missing required field: chatId",
  "details": "Additional error information (optional)"
}

Authentication errors (401):

{
  "success": false,
  "error": "Unauthorized"
}

Deployment

See DEPLOYMENT.md for detailed production deployment instructions.

Quick deployment:

# Deploy to production
npm run deploy

API Reference

See API_REFERENCE.md for complete API documentation including:

  • Detailed endpoint specifications
  • Request/response schemas
  • Error codes and messages
  • Advanced usage examples

Project Structure

telegram-worker/
├── src/
│   ├── index.ts              # Worker entry point and routing
│   ├── types.ts              # TypeScript type definitions
│   ├── handlers/
│   │   ├── message.ts        # /send-message endpoint handler
│   │   └── profile.ts        # /profiles endpoint handlers
│   ├── services/
│   │   ├── telegram.ts       # Telegram Bot API integration
│   │   └── database.ts       # D1 database operations
│   └── utils/
│       └── validation.ts     # Input validation functions
├── examples/                 # Example cURL scripts
├── schema.sql               # Database schema
├── wrangler.toml           # Cloudflare Worker configuration
├── package.json            # Node.js dependencies
├── tsconfig.json           # TypeScript configuration
├── README.md               # This file
├── docs/
│   ├── API_REFERENCE.md    # Detailed API documentation
│   └── DEPLOYMENT.md       # Deployment guide

Development Commands

# Start local development server
npm run dev

# Format code with Biome
npm run format

# Lint code with Biome
npm run lint

# Run both formatting and linting
npm run check

# Deploy to production
npm run deploy

Troubleshooting

Authentication Errors

"Unauthorized" (401 response)

This error indicates authentication failure. All requests except OPTIONS must include a valid Bearer token.

Common causes:

  1. Missing Authorization header

    # Wrong - no Authorization header
    curl https://your-worker.workers.dev/profiles
    
    # Correct
    curl https://your-worker.workers.dev/profiles \
      -H "Authorization: Bearer YOUR_API_TOKEN"
  2. Incorrect token format

    # Wrong - missing "Bearer " prefix
    curl -H "Authorization: YOUR_API_TOKEN" ...
    
    # Wrong - typo in "Bearer"
    curl -H "Authorization: Bearar YOUR_API_TOKEN" ...
    
    # Correct
    curl -H "Authorization: Bearer YOUR_API_TOKEN" ...
  3. Invalid token value

    • Verify you're using the correct token
    • Check the token was set correctly: wrangler secret list
    • Ensure there are no extra spaces or newlines in the token
    • Try regenerating and setting a new token
  4. Token not set in Cloudflare

    # Set the API token
    wrangler secret put API_TOKEN

Security note: For security reasons, all authentication failures return the same generic "Unauthorized" message without details about what failed.

Telegram API Errors

"Bot was blocked by the user"

The user has blocked your bot. Ask them to unblock it or remove that chat ID from your profile.

"Forbidden: bot is not a member of the supergroup chat"

Your bot needs to be added to the group/channel as a member (or admin for channels).

"Unauthorized: bot token is invalid"

Check that your Telegram bot token is correct. Generate a new token via @BotFather if needed.

"Chat not found"

Verify the chat ID is correct. Make sure it's a string and includes the negative sign for groups.

"Bad Request: message text is empty"

Ensure your content field contains text. Empty strings are not allowed.

Database Errors

If you see D1 database errors:

  1. Verify the database exists: wrangler d1 list
  2. Check the schema is applied: wrangler d1 execute telegram_worker_db --local --command "SELECT * FROM profiles LIMIT 1"
  3. Verify wrangler.toml has the correct database_id

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Submit a pull request

License

ISC License - see LICENSE file for details

Support

For issues and questions:

Acknowledgments

About

A Cloudflare Worker for forwarding messages to Telegram chats using the Telegram Bot API. This service provides a REST API for sending messages to single or multiple Telegram chats, with support for reusable profile configurations.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published