Skip to main content

Telegram Bot Connector

Send and receive messages through the Telegram Bot API.

Package

dotnet add package Ratatosk.Telegram

Required settings

ParameterTypeDescription
BotTokenstringTelegram Bot token from BotFather (format: 123456:ABC...)

Optional settings

ParameterTypeDefaultDescription
WebhookUrlstringPublic HTTPS URL for receiving updates
SecretTokenstringSecret token for webhook request validation
ParseModestringDefault parse mode: MarkdownV2, HTML, or Markdown

The Bot token is obtained from @BotFather on Telegram. The webhook URL must be HTTPS.

Schema

PropertyValue
ProviderTelegram
TypeBot
Version1.0.0
CapabilitiesSendMessages, ReceiveMessages, MediaAttachments, InteractiveContent
Content typesPlainText, Media, Button, QuickReply
EndpointsId (chat ID)
AuthenticationToken (bot token)

Send examples

Text message

var settings = new ConnectionSettings()
.SetParameter("BotToken", "123456:ABC...");

var connector = new TelegramBotConnector(TelegramChannelSchemas.SimpleTelegramBot, settings);
await connector.InitializeAsync(ct);

var message = new MessageBuilder()
.WithId("tg-1")
.To(Endpoint.Id("123456789"))
.WithText("Hello from Telegram Bot!")
.Build();

var result = await connector.SendMessageAsync(message, ct);

Rich text with MarkdownV2

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithText("*bold* _italic_ `code` [link](https://example.com)")
.WithParseMode("MarkdownV2")
.Build();

Rich text with HTML

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithText("<b>bold</b> <i>italic</i> <code>code</code>")
.WithParseMode("HTML")
.Build();

Image

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithContent(new MediaContent(MediaType.Image, "photo.jpg",
"https://example.com/photo.jpg"))
.Build();

Document

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithContent(new MediaContent(MediaType.Document, "report.pdf",
null, pdfFileBytes))
.Build();

Image with caption

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithContent(new MediaContent(MediaType.Image, "photo.jpg",
"https://example.com/photo.jpg"))
.WithCaption("Check out this photo!")
.Build();

Location

new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithContent(new LocationContent(41.9028, 12.4964)
.WithHorizontalAccuracy(10))
.Build();

Message with inline buttons

// The button text is used as the message body
new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithButton("What would you like to do?", ButtonType.Url, "https://example.com")
.Build();

Message with quick reply keyboard

// Single quick reply option
new MessageBuilder()
.To(Endpoint.Id("123456789"))
.WithQuickReply("Yes", "YES_PAYLOAD")
.Build();

Message properties

PropertyTypeDescription
ParseModestringText formatting: MarkdownV2, HTML, Markdown
captionstringCaption for media messages (max 1024 chars)
disable_notificationboolSend silently
protect_contentboolDisable forwarding and saving
reply_to_message_idintID of the message to reply to
allow_sending_without_replyboolAllow reply even if the original message not found

Webhook setup

1. Configure webhook

Set the webhook URL in connection settings:

var settings = new ConnectionSettings()
.SetParameter("BotToken", "123456:ABC...")
.SetParameter("WebhookUrl", "https://yourdomain.com/webhooks/telegram")
.SetParameter("SecretToken", "your-secret-token");

2. Handle incoming updates

[HttpPost("/webhooks/telegram")]
public async Task<IActionResult> TelegramWebhook(CancellationToken ct)
{
// Validate secret token
var secretToken = Request.Headers["X-Telegram-Bot-Api-Secret-Token"].FirstOrDefault();
if (secretToken != expectedSecretToken)
return Unauthorized();

// Read the update
using var reader = new StreamReader(Request.Body);
var body = await reader.ReadToEndAsync(ct);
var source = MessageSource.Json(body);

// Process inbound messages
var result = await _connector.ReceiveMessagesAsync(source, ct);

if (result.IsSuccess)
{
foreach (var message in result.Data?.Messages ?? [])
{
var text = (message.Content as TextContent)?.Text;
Console.WriteLine($"Received from {message.Sender?.Address}: {text}");

// Auto-reply
var reply = new MessageBuilder()
.WithId(Guid.NewGuid().ToString("n"))
.To(message.Sender!)
.WithText($"Echo: {text}")
.Build();

await _connector.SendMessageAsync(reply, ct);
}
}

return Ok(); // Telegram expects 200 OK
}

Error codes

Telegram-specific error codes are defined in TelegramErrorCodes with domain "Telegram".

CodeDescription
INVALID_CHAT_IDChat ID is missing or invalid
FILE_TOO_LARGEFile exceeds Telegram size limits
INVALID_MEDIA_URLMedia URL is not valid
BOT_BLOCKEDBot was blocked by the user
CHAT_NOT_FOUNDChat does not exist or bot cannot access it
UNAUTHORIZEDBot token is invalid or unauthorized

Standard MessagingErrorCodes are also used — see the error codes reference.

Original provider codes

Telegram Bot API errors (ApiRequestException) are mapped to framework error codes via two mapping methods in TelegramService:

MapTelegramErrorCode (getMe, initialization):

Telegram codeMapped framework code
400INVALID_CREDENTIALS
401UNAUTHORIZED
403BOT_BLOCKED
404CHAT_NOT_FOUND
429UNSUPPORTED_CONTENT_TYPE
OtherUNAUTHORIZED

MapTelegramSendErrorCode (sendMessage, sendPhoto, etc.):

Telegram codeMapped framework code
400INVALID_CHAT_ID
403BOT_BLOCKED
404CHAT_NOT_FOUND
429UNSUPPORTED_CONTENT_TYPE
OtherUNSUPPORTED_CONTENT_TYPE

Troubleshooting

SymptomLikely causeFix
INVALID_CREDENTIALSWrong bot tokenRe-generate token from BotFather
INVALID_RECIPIENTChat ID doesn't exist or bot can't messageUser must /start the bot first
PROVIDER_VALIDATION_FAILEDInvalid message formatCheck ParseMode escaping rules
Message too longExceeds 4096 charactersSplit into multiple messages using reply_to_message_id
Bot blockedUser blocked the botRemove chat ID from your store
Webhook not receivingHTTPS requiredTelegram only accepts HTTPS webhook URLs
Webhook failsSecret token mismatchVerify SecretToken matches what Telegram sent

TelegramChannelSchemas

// Simple Telegram bot schema (send only)
TelegramChannelSchemas.SimpleTelegramBot