Skip to main content
This guide will walk you through creating a fully functional Telegram bot using Telegrator. You’ll learn the fundamental concepts and have a working bot by the end.

What You’ll Build

By the end of this guide, you’ll have a bot that:
  • Responds to the /start command
  • Handles text messages
  • Uses filters to control when handlers execute
  • Demonstrates the mediator-based architecture

Choose Your Approach

Best for simple bots or learning the framework

Basic Bot (Core Package)

Step 1: Create a New Project

1

Create console application

dotnet new console -n MyTelegramBot
cd MyTelegramBot
2

Install Telegrator

dotnet add package Telegrator

Step 2: Create Your First Handler

Create a new file called StartCommandHandler.cs:
StartCommandHandler.cs
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegrator.Handlers;
using Telegrator.Annotations;

[CommandHandler]
[CommandAlias("start", "hello")]
[ChatType(ChatType.Private)]
public class StartCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        string username = Input.From?.FirstName ?? "friend";
        await Response($"Hello, {username}! Welcome to my bot!", cancellationToken: cancellation);
        return Result.Ok();
    }
}
The [CommandHandler] attribute marks this class as a command handler, while [CommandAlias] specifies which commands trigger it (both /start and /hello will work).

Step 3: Create a Message Handler

Create EchoHandler.cs to respond to all text messages:
EchoHandler.cs
using Telegram.Bot.Types;
using Telegrator.Handlers;
using Telegrator.Annotations;

[MessageHandler]
public class EchoHandler : MessageHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        if (Input.Text != null)
        {
            await Reply($"You said: {Input.Text}", cancellationToken: cancellation);
        }
        
        return Result.Ok();
    }
}

Step 4: Initialize and Start the Bot

Update your Program.cs:
Program.cs
using Telegrator;

// Create bot client with your token from BotFather
var bot = new TelegratorClient("YOUR_BOT_TOKEN_HERE");

// Register handlers
bot.Handlers.AddHandler<StartCommandHandler>();
bot.Handlers.AddHandler<EchoHandler>();

// Start receiving updates
Console.WriteLine("Bot is starting...");
bot.StartReceiving();

// Keep the application running
Console.WriteLine("Bot is running. Press any key to stop.");
Console.ReadKey();

Step 5: Run Your Bot

dotnet run
Get your bot token from @BotFather on Telegram. Never commit tokens to source control!
For production applications, use the Hosting package with dependency injection and configuration.

Step 1: Create Project and Install Packages

dotnet new console -n MyHostedBot
cd MyHostedBot
dotnet add package Telegrator.Hosting

Step 2: Create appsettings.json

appsettings.json
{
  "TelegramBotClientOptions": {
    "Token": "YOUR_BOT_TOKEN_HERE"
  },
  "ReceiverOptions": {
    "DropPendingUpdates": true,
    "Limit": 100
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Telegrator": "Debug"
    }
  }
}
Make sure to set “Copy to Output Directory” to “Copy if newer” for appsettings.json in your .csproj:
<ItemGroup>
  <None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Step 3: Create Handlers

Create Handlers/StartCommandHandler.cs:
Handlers/StartCommandHandler.cs
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegrator.Handlers;
using Telegrator.Annotations;

namespace MyHostedBot.Handlers;

[CommandHandler]
[CommandAlias("start")]
[ChatType(ChatType.Private)]
public class StartCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        string message = $"""
            Welcome to my bot! 
            
            Available commands:
            /start - Show this message
            /help - Get help
            /echo [text] - Echo your message
            """;
            
        await Response(message, cancellationToken: cancellation);
        return Result.Ok();
    }
}
Create Handlers/HelpCommandHandler.cs:
Handlers/HelpCommandHandler.cs
using Telegram.Bot.Types;
using Telegrator.Handlers;
using Telegrator.Annotations;

namespace MyHostedBot.Handlers;

[CommandHandler]
[CommandAlias("help")]
public class HelpCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        await Response(
            "This bot demonstrates Telegrator framework features. Try sending me a message!",
            cancellationToken: cancellation
        );
        return Result.Ok();
    }
}
Create Handlers/EchoCommandHandler.cs:
Handlers/EchoCommandHandler.cs
using Telegram.Bot.Types;
using Telegrator.Handlers;
using Telegrator.Annotations;

namespace MyHostedBot.Handlers;

[CommandHandler]
[CommandAlias("echo")]
public class EchoCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        if (string.IsNullOrWhiteSpace(ArgumentsString))
        {
            await Response("Usage: /echo <text>", cancellationToken: cancellation);
        }
        else
        {
            await Response($"Echo: {ArgumentsString}", cancellationToken: cancellation);
        }
        
        return Result.Ok();
    }
}
The ArgumentsString property in CommandHandler provides everything after the command, while Arguments gives you an array of individual arguments.

Step 4: Update Program.cs

Program.cs
using Telegrator.Hosting;

// Create builder with settings
TelegramBotHostBuilder builder = TelegramBotHost.CreateBuilder(
    new TelegramBotHostBuilderSettings()
    {
        Args = args,
        ExceptIntersectingCommandAliases = true
    }
);

// Automatically discover and register all handlers in the assembly
builder.Handlers.CollectHandlersAssemblyWide();

// Optional: Register custom services
// builder.Services.AddSingleton<IMyService, MyService>();

// Build the host
TelegramBotHost telegramBot = builder.Build();

// Set bot commands in Telegram UI
telegramBot.SetBotCommands();

// Add logging adapter to connect Telegrator logs with Microsoft.Extensions.Logging
telegramBot.AddLoggingAdapter();

// Run the bot
Console.WriteLine("Bot is starting...");
telegramBot.Run();

Step 5: Run the Bot

dotnet run
The CollectHandlersAssemblyWide() method automatically discovers and registers all handlers in your assembly. You can also register handlers individually using builder.Handlers.AddHandler<T>().

Web Bot (Webhooks)

For ASP.NET Core applications using webhooks instead of long polling.

Step 1: Create and Configure Project

dotnet new web -n MyWebBot
cd MyWebBot
dotnet add package Telegrator.Hosting.Web

Step 2: Create appsettings.json

appsettings.json
{
  "TelegramBotClientOptions": {
    "Token": "YOUR_BOT_TOKEN_HERE"
  },
  "TelegratorWebOptions": {
    "WebhookUri": "https://your-domain.com/bot",
    "DropPendingUpdates": true
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Telegrator": "Debug"
    }
  }
}
For webhooks, you need a publicly accessible HTTPS URL. Telegram requires SSL/TLS. For local development, use tools like ngrok or localtunnel.

Step 3: Create Handlers

Use the same handlers as in the hosted example above.

Step 4: Configure Program.cs

Program.cs
using Telegrator.Hosting;
using Telegrator.Hosting.Web;

// Create web host builder
TelegramBotWebHostBuilder builder = TelegramBotWebHost.CreateBuilder(
    new TelegramBotWebOptions()
    {
        Args = args,
        ExceptIntersectingCommandAliases = true
    }
);

// Register handlers
builder.Handlers.CollectHandlersAssemblyWide();

// Optional: Add your services
// builder.Services.AddSingleton<IMyService, MyService>();

// Build and configure
TelegramBotWebHost telegramBot = builder.Build();
telegramBot.SetBotCommands();
telegramBot.AddLoggingAdapter();

// Run the web application
Console.WriteLine("Web bot is starting...");
telegramBot.Run();

Understanding Handler Priority

Handlers execute based on their importance level. You can control execution order:
[CommandHandler(importance: 10)]  // Higher importance = executes first
[CommandAlias("admin")]
public class AdminCommandHandler : CommandHandler
{
    // This handler will execute before handlers with lower importance
}

[MessageHandler(importance: 0)]  // Default importance
public class GeneralMessageHandler : MessageHandler
{
    // This handler executes after high-importance handlers
}
The importance parameter in handler attributes controls execution order. Higher values execute first. Default is 0 for messages and 1 for commands.

Using Filters

Filters control when handlers execute. Combine multiple filters for precise control:
using Telegram.Bot.Types.Enums;
using Telegrator.Handlers;
using Telegrator.Annotations;

[CommandHandler]
[CommandAlias("admin")]
[ChatType(ChatType.Private)]  // Only in private chats
[SenderId(123456789)]          // Only for specific user
public class AdminCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IAbstractHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        await Response("Admin panel loading...", cancellationToken: cancellation);
        return Result.Ok();
    }
}
Common filter attributes:
  • [ChatType(ChatType.Private)] - Filter by chat type
  • [SenderId(id)] - Filter by sender ID
  • [ChatId(id)] - Filter by chat ID
  • [TextContains("word")] - Filter messages containing text
  • [TextRegex(@"pattern")] - Filter by regex pattern

Next Steps

Handlers & Filters

Learn about all available handler types and filters

State Management

Handle user conversations and multi-step workflows

Dependency Injection

Use services and DI in your handlers

Error Handling

Gracefully handle errors and exceptions

Common Patterns

Responding vs Replying

// Response - sends a new message to the chat
await Response("Hello!");

// Reply - replies to the message that triggered the handler
await Reply("Hello!");  // Shows as a reply in Telegram

Accessing Update Data

public override async Task<Result> Execute(
    IAbstractHandlerContainer<Message> container, 
    CancellationToken cancellation)
{
    // Access the message that triggered this handler
    Message message = Input;
    
    // Access user information
    long userId = message.From?.Id ?? 0;
    string username = message.From?.Username ?? "unknown";
    
    // Access chat information
    long chatId = message.Chat.Id;
    ChatType chatType = message.Chat.Type;
    
    // Access message content
    string? text = message.Text;
    
    await Response($"User {username} (ID: {userId}) in chat {chatId}");
    return Result.Ok();
}

Returning Results

// Success - handler completed successfully, stop routing
return Result.Ok();

// Error - handler encountered an error, stop routing
return Result.Fault();

// Continue - let the router continue to other handlers
return Result.Next();

// Chain - continue only to handlers of specific type
return Result.Next<CommandHandler>();
Explore the GitHub repository for more examples and the complete source code!

Build docs developers (and LLMs) love