Skip to main content
Version: v1.0.6

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
WebhookUrlstring—Public HTTPS URL for receiving updates
SecretTokenstring—Secret token for webhook request validation
ParseModestring—Default 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