Telegram API
Schedule and automate Telegram channel and group posts with Zernio API - Text, images, videos, media albums, silent messages, and bot management
Quick Reference
| Property | Value |
|---|---|
| Text limit | 4,096 characters (text messages) |
| Caption limit | 1,024 characters (media captions) |
| Images per album | 10 |
| Videos per album | 10 |
| Mixed media | Yes (images + videos in same album) |
| Image formats | JPEG, PNG, GIF, WebP |
| Image max size | 10 MB (auto-compressed) |
| Video formats | MP4, MOV |
| Video max size | 50 MB (auto-compressed) |
| Scheduling | Yes |
| Inbox (DMs) | Yes (add-on, full featured) |
| Inbox (Comments) | No |
| Analytics | No (Telegram limitation) |
Before You Start
Telegram requires @ZernioScheduleBot to be an administrator in your channel or group with post permissions. This is the number one setup failure. Also: posts in groups show as sent by "ZernioScheduleBot", not by you. In channels, posts show as the channel name.
Additional requirements:
- Bot-based integration (not OAuth). Uses
@ZernioScheduleBot - The bot must be added as an admin with post permissions before you can publish
- Channels: posts appear as the channel name and logo (correct behavior)
- Groups: posts appear as "ZernioScheduleBot" (cannot be changed)
Quick Start
Post to a Telegram channel or group:
const { post } = await zernio.posts.createPost({
content: 'Hello from Zernio API! Check out our latest update.',
platforms: [
{ platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to Telegram!', post._id);result = client.posts.create(
content="Hello from Zernio API! Check out our latest update.",
platforms=[
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to Telegram! {post['_id']}")curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from Zernio API! Check out our latest update.",
"platforms": [
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Content Types
Text Message
Send a formatted text message with HTML, Markdown, or MarkdownV2:
const { post } = await zernio.posts.createPost({
content: '<b>Important Update!</b>\n\nCheck out our <a href="https://example.com">new feature</a>.',
platforms: [{
platform: 'telegram',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
parseMode: 'HTML'
}
}],
publishNow: true
});result = client.posts.create(
content='<b>Important Update!</b>\n\nCheck out our <a href="https://example.com">new feature</a>.',
platforms=[{
"platform": "telegram",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"parseMode": "HTML"
}
}],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "<b>Important Update!</b>\n\nCheck out our <a href=\"https://example.com\">new feature</a>.",
"platforms": [{
"platform": "telegram",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"parseMode": "HTML"
}
}],
"publishNow": true
}'Photo Message
Send a single image with an optional caption:
const { post } = await zernio.posts.createPost({
content: 'Check out this photo!',
mediaItems: [
{ type: 'image', url: 'https://example.com/image.jpg' }
],
platforms: [
{ platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});result = client.posts.create(
content="Check out this photo!",
media_items=[
{"type": "image", "url": "https://example.com/image.jpg"}
],
platforms=[
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Check out this photo!",
"mediaItems": [
{"type": "image", "url": "https://example.com/image.jpg"}
],
"platforms": [
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Video Message
Send a single video with an optional caption:
const { post } = await zernio.posts.createPost({
content: 'Watch our latest video!',
mediaItems: [
{ type: 'video', url: 'https://example.com/video.mp4' }
],
platforms: [
{ platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});result = client.posts.create(
content="Watch our latest video!",
media_items=[
{"type": "video", "url": "https://example.com/video.mp4"}
],
platforms=[
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Watch our latest video!",
"mediaItems": [
{"type": "video", "url": "https://example.com/video.mp4"}
],
"platforms": [
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Document Message
Send any file type as a document:
const { post } = await zernio.posts.createPost({
content: 'Here is the report.',
mediaItems: [
{ type: 'document', url: 'https://example.com/report.pdf' }
],
platforms: [
{ platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});result = client.posts.create(
content="Here is the report.",
media_items=[
{"type": "document", "url": "https://example.com/report.pdf"}
],
platforms=[
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Here is the report.",
"mediaItems": [
{"type": "document", "url": "https://example.com/report.pdf"}
],
"platforms": [
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Media Album
Send up to 10 items in a single album. Images and videos can be mixed:
const { post } = await zernio.posts.createPost({
content: 'Our latest product gallery!',
mediaItems: [
{ type: 'image', url: 'https://example.com/image1.jpg' },
{ type: 'image', url: 'https://example.com/image2.jpg' },
{ type: 'video', url: 'https://example.com/video.mp4' },
{ type: 'image', url: 'https://example.com/image3.jpg' }
],
platforms: [
{ platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});result = client.posts.create(
content="Our latest product gallery!",
media_items=[
{"type": "image", "url": "https://example.com/image1.jpg"},
{"type": "image", "url": "https://example.com/image2.jpg"},
{"type": "video", "url": "https://example.com/video.mp4"},
{"type": "image", "url": "https://example.com/image3.jpg"}
],
platforms=[
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Our latest product gallery!",
"mediaItems": [
{"type": "image", "url": "https://example.com/image1.jpg"},
{"type": "image", "url": "https://example.com/image2.jpg"},
{"type": "video", "url": "https://example.com/video.mp4"},
{"type": "image", "url": "https://example.com/image3.jpg"}
],
"platforms": [
{"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Media Requirements
Images
| Property | Requirement |
|---|---|
| Max per album | 10 |
| Formats | JPEG, PNG, GIF, WebP |
| Max file size | 10 MB (auto-compressed) |
| Max resolution | 10,000 x 10,000 px |
Videos
| Property | Requirement |
|---|---|
| Max per album | 10 |
| Formats | MP4, MOV |
| Max file size | 50 MB (auto-compressed) |
| Max duration | No limit |
| Codec | H.264 recommended |
Platform-Specific Fields
All fields go inside platformSpecificData for the Telegram platform entry:
| Field | Type | Default | Description |
|---|---|---|---|
parseMode | string | "HTML" | Text formatting mode: "HTML", "Markdown", or "MarkdownV2" |
disableWebPagePreview | boolean | false | Prevents link preview generation for URLs in the message |
disableNotification | boolean | false | Sends the message silently (recipients get no notification sound) |
protectContent | boolean | false | Prevents the message from being forwarded or saved by recipients |
const { post } = await zernio.posts.createPost({
content: '<b>Important Update!</b>\n\nCheck out our <a href="https://example.com">new feature</a>.',
platforms: [{
platform: 'telegram',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
parseMode: 'HTML',
disableWebPagePreview: false,
disableNotification: true,
protectContent: true
}
}],
publishNow: true
});result = client.posts.create(
content='<b>Important Update!</b>\n\nCheck out our <a href="https://example.com">new feature</a>.',
platforms=[{
"platform": "telegram",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"parseMode": "HTML",
"disableWebPagePreview": False,
"disableNotification": True,
"protectContent": True
}
}],
publish_now=True
)curl -X POST https://zernio.com/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "<b>Important Update!</b>\n\nCheck out our <a href=\"https://example.com\">new feature</a>.",
"platforms": [{
"platform": "telegram",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"parseMode": "HTML",
"disableWebPagePreview": false,
"disableNotification": true,
"protectContent": true
}
}],
"publishNow": true
}'Connection
Zernio provides a managed bot (@ZernioScheduleBot) for Telegram integration. No need to create your own bot -- just add Zernio's bot to your channel or group.
Option 1: Access Code Flow (Recommended)
This is the easiest way to connect a Telegram channel or group.
Step 1: Generate an Access Code
const { code, botUsername, instructions } = await zernio.connect.getConnectUrl({
platform: 'telegram',
profileId: 'YOUR_PROFILE_ID'
});
console.log(`Your access code: ${code}`);
console.log(`Bot to message: @${botUsername}`);result = client.connect.get_connect_url(
platform="telegram",
profile_id="YOUR_PROFILE_ID"
)
print(f"Your access code: {result.code}")
print(f"Bot to message: @{result.bot_username}")curl -X GET "https://zernio.com/api/v1/connect/telegram?profileId=YOUR_PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"Response:
{
"code": "ZERNIO-ABC123",
"expiresAt": "2025-01-15T12:30:00.000Z",
"expiresIn": 900,
"botUsername": "ZernioScheduleBot",
"instructions": [
"1. Add @ZernioScheduleBot as an administrator in your channel/group",
"2. Open a private chat with @ZernioScheduleBot",
"3. Send: ZERNIO-ABC123 @yourchannel (replace @yourchannel with your channel username)",
"4. Wait for confirmation - the connection will appear in your dashboard",
"Tip: If your channel has no public username, forward a message from it along with the code"
]
}Step 2: Add the Bot to Your Channel/Group
For Channels:
- Go to your channel settings
- Add
@ZernioScheduleBotas an Administrator - Grant permission to Post Messages
For Groups:
- Add
@ZernioScheduleBotto the group - Make the bot an Administrator (required for posting)
Step 3: Send the Access Code
- Open a private chat with @ZernioScheduleBot
- Send your access code with your channel:
ZERNIO-ABC123 @yourchannel - For private channels without a username, forward any message from the channel to the bot along with the code
Step 4: Poll for Connection Status
const checkStatus = async (code) => {
const status = await zernio.connect.checkTelegramConnection({ code });
return status;
};
const pollConnection = async (code) => {
while (true) {
const status = await checkStatus(code);
if (status.status === 'connected') {
console.log(`Connected to ${status.chatTitle}!`);
console.log(`Account ID: ${status.account._id}`);
return status.account;
}
if (status.status === 'expired') {
throw new Error('Access code expired. Generate a new one.');
}
await new Promise(resolve => setTimeout(resolve, 3000));
}
};import time
def check_status(code):
return client.connect.check_telegram_connection(code=code)
def poll_connection(code):
while True:
status = check_status(code)
if status['status'] == 'connected':
print(f"Connected to {status['chatTitle']}!")
print(f"Account ID: {status['account']['_id']}")
return status['account']
if status['status'] == 'expired':
raise Exception('Access code expired. Generate a new one.')
time.sleep(3)curl -X PATCH "https://zernio.com/api/v1/connect/telegram?code=ZERNIO-ABC123" \
-H "Authorization: Bearer YOUR_API_KEY"Status Response (Pending):
{
"status": "pending",
"expiresAt": "2025-01-15T12:30:00.000Z",
"expiresIn": 542
}Status Response (Connected):
{
"status": "connected",
"chatId": "-1001234567890",
"chatTitle": "My Channel",
"chatType": "channel",
"account": {
"_id": "64e1f0a9e2b5af0012ab34cd",
"platform": "telegram",
"username": "mychannel",
"displayName": "My Channel"
}
}Option 2: Direct Connection (Power Users)
If you already know your chat ID and the Zernio bot is already an administrator in your channel/group:
const { account } = await zernio.connect.connectTelegram({
profileId: 'YOUR_PROFILE_ID',
chatId: '-1001234567890'
});
console.log('Connected:', account._id);result = client.connect.connect_telegram(
profile_id="YOUR_PROFILE_ID",
chat_id="-1001234567890"
)
print(f"Connected: {result['account']['_id']}")curl -X POST https://zernio.com/api/v1/connect/telegram \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "YOUR_PROFILE_ID",
"chatId": "-1001234567890"
}'Response:
{
"message": "Telegram channel connected successfully",
"account": {
"_id": "64e1f0a9e2b5af0012ab34cd",
"platform": "telegram",
"username": "mychannel",
"displayName": "My Channel",
"isActive": true,
"chatType": "channel"
}
}Finding Your Chat ID
For Public Channels:
- Use the channel username with
@prefix:@mychannel
For Private Channels:
- Forward a message from the channel to @userinfobot
- The bot will reply with the numeric chat ID (starts with
-100)
For Groups:
- Add @userinfobot to your group temporarily
- It will display the group's chat ID (negative number)
- Remove the bot after getting the ID
Text Formatting
HTML Mode (Default)
<b>bold</b>
<i>italic</i>
<u>underline</u>
<s>strikethrough</s>
<code>inline code</code>
<pre>code block</pre>
<a href="https://example.com">link</a>Markdown Mode
*bold*
_italic_
[link](https://example.com)
`inline code`MarkdownV2 Mode
*bold*
_italic_
__underline__
~strikethrough~
||spoiler||
`inline code`Note: MarkdownV2 requires escaping special characters:
_,*,[,],(,),~,`,>,#,+,-,=,|,{,},.,!
Channel vs Group Posts
| Destination | Author Display |
|---|---|
| Channel | Channel name and logo |
| Group | Bot name (ZernioScheduleBot) |
When posting to a channel, the post appears as if sent by the channel itself. When posting to a group, the post shows as sent by the Zernio bot.
Analytics
Telegram does not provide analytics through its Bot API. View counts for channel posts are only visible within the Telegram app. For messaging metrics, use Telegram's native channel statistics (available for channels with 500+ subscribers).
What You Can't Do
- Create polls or quizzes via Zernio
- Schedule messages natively through Telegram (use Zernio scheduling instead)
- Manage channel administrators
- See message analytics (Telegram platform limitation)
- Pin messages
- Create channel invite links
Common Errors
| Error | Cause | Fix |
|---|---|---|
| "Bot is not a member of the channel" | @ZernioScheduleBot is not added to the channel/group or is not an admin | Add the bot as an administrator and grant post permissions |
| "Message is too long" | Text exceeds 4,096 characters or caption exceeds 1,024 characters | Shorten the content or split into multiple messages |
| "Wrong file identifier/HTTP URL specified" | Media URL is inaccessible, uses HTTP, or redirects | Use a direct HTTPS URL that is publicly accessible with no redirects |
| "Can't parse entities" | Invalid HTML/Markdown syntax or unescaped special characters | Check tag closure in HTML mode; escape special characters in MarkdownV2 |
| Media not displaying | Unsupported format or file exceeds size limit | Verify format is supported and size is within limits (10 MB images, 50 MB videos) |
| "Access code expired" | Code was not used within 15 minutes | Generate a new access code with GET /v1/connect/telegram |
Inbox
Requires Inbox add-on — Build: +$10/mo · Accelerate: +$50/unit · Unlimited: +$1,000/mo
Telegram supports DMs with full attachment support.
Direct Messages
| Feature | Supported |
|---|---|
| List conversations | Yes |
| Fetch messages | Yes |
| Send text messages | Yes |
| Send attachments | Yes (images, videos, documents) |
| Edit messages | Yes (text and inline keyboard) |
| Inline keyboards | Yes (buttons with callback data or URLs) |
| Reply keyboards | Yes (one-time custom keyboards) |
| Reply to message | Yes (via replyTo message ID) |
| Archive/unarchive | Yes |
Attachment Support
| Type | Supported | Max Size |
|---|---|---|
| Images | Yes | 10 MB |
| Videos | Yes | 50 MB |
| Documents | Yes | 50 MB |
Bot Commands
Manage the bot command menu shown in Telegram chats. Commands appear in the "/" menu when users interact with the bot.
See Account Settings for the GET/PUT/DELETE /v1/accounts/{accountId}/telegram-commands endpoints.
Webhooks
Subscribe to message.received to get notified when new DMs arrive. Messages are stored locally via webhooks.
Notes
- Bot-based - Uses bot tokens, not OAuth
- Messages are stored locally when received via webhooks
- Incoming callback data from inline keyboard taps is available in message
metadata.callbackData
See Messages API Reference for endpoint details.
Related Endpoints
- Connect Telegram Account - Access code connection flow
- Create Post - Post creation and scheduling
- Upload Media - Image and video uploads
- Messages - Inbox conversations and DMs
- Account Settings - Bot commands configuration