Telegram
Post to Telegram channels and groups programmatically using the PostPost REST API. A simpler alternative to the Telegram Bot API, Telethon, Pyrogram, or MTProto libraries.
Telegram API Overview
PostPost provides a unified REST API for publishing content to Telegram channels and groups via bot or MTProto connection. Supports rich text formatting with markdown syntax, images, and videos. No need to manage Telegram bot tokens directly, handle MTProto complexity, or implement message queuing. PostPost supports two connection types: bot (using a BotFather token) and mtproto (using a user session), each with different capabilities and limits.
Why Use PostPost Instead of Telegram Bot API / Telethon / Pyrogram?
| Feature | PostPost API | Telegram Bot API / Telethon |
|---|---|---|
| Authentication | Single API key | Bot token + channel setup |
| Message formatting | Markdown support | Markdown/HTML support |
| Media handling | Automatic | Manual upload |
| Multi-platform | Post to 11 platforms | Telegram only |
| Setup time | 5 minutes | 15-30 minutes |
| Rate limiting | Handled | Manual implementation |
Keywords: Telegram API, Telegram Bot API, Telegram channel API, Telegram posting API, post to Telegram programmatically, Telegram REST API, Telegram developer API, Telegram automation API, Telegram message API, send message Telegram API, Telethon alternative, Pyrogram alternative, MTProto API
Platform ID Format
telegram-{chatId}Where {chatId} is your Telegram channel or group chat ID assigned during bot connection setup.
Requirements
- A Telegram bot created via @BotFather
- The bot's token and target channel/group name provided during setup
- The bot must be added as an administrator of the target channel or group with the
can_post_messagespermission explicitly enabled (being an admin alone is not enough) - API key from PostPost
Connection Types
PostPost supports two connection types for Telegram:
Bot Connection (Default)
- Create a bot with @BotFather on Telegram
- Copy the bot token provided by BotFather
- Add the bot as an administrator to your target channel or group
- In the PostPost dashboard, provide the bot token and channel name (e.g.,
@mychannel) - PostPost will verify the connection and assign a platform ID
MTProto Connection
MTProto connections use a Telegram user session instead of a bot, enabling higher limits (2,048-character captions with Premium, 4 GB file uploads). MTProto requires a Telegram Premium subscription on the service user account. Note: PostPost's code enforces a 4,096-character limit for all text fields, but Telegram's actual caption limit on media posts is 1,024 characters (regular users) or 2,048 characters (Premium). The 4,096 limit applies only to text-only messages. Long captions on media posts may be truncated or rejected by Telegram's API.
Service user concept: The MTProto connection operates through a dedicated Telegram user account (the "service user") that acts on behalf of your organization. This user must be an admin of the target channel/group. Because the service user is a regular Telegram account (not a bot), it benefits from the higher user-tier limits. The service user's session is stored encrypted by PostPost in the connection record and decrypted at runtime.
Note: MTProto connections require the service user to have an active Telegram Premium subscription. Without Premium, certain features (such as the extended 2,048-character caption limit on media posts) will not be available. For self-hosted deployments, the
TELEGRAM_MT_ALLOW_NON_PREMIUMenvironment variable can be set to bypass the Premium requirement for MTProto connections.
Supported Content
| Type | Supported | Limits |
|---|---|---|
| Text | Yes | 4,096 characters (text-only messages, both bot and MTProto); 1,024 characters (captions with media, bot API) |
| Images | Yes | JPEG, PNG, GIF, BMP, WebP (WebP auto-converted to JPEG) |
| Videos | Yes | MP4, MOV, AVI, MKV, WebM |
| Formatting | Yes | Bold, italic, code, links, blockquotes |
Text Formatting
Telegram supports markdown-style formatting in message text. You can use the following syntax in your content:
| Syntax | Result | Example |
|---|---|---|
*text* | Bold | *important* |
_text_ | Italic | _emphasis_ |
`code` | Inline code | `variable` |
```code``` | Code block | ```print("hello")``` |
[text](url) | Hyperlink | [click here](https://example.com) |
> text | Blockquote | > quoted text |
Caption vs. Message
When posting with media (images or videos), the text content is sent as a caption attached to the media. Captions have a stricter limit of 1,024 characters when using the bot API. MTProto with Premium supports up to 2,048-character captions on media posts (not 4,096 -- the 4,096 limit applies only to text-only messages). Text-only messages (without media) support up to 4,096 characters for both bot API and MTProto connections.
Telegram Post Options
PostPost supports Telegram-specific post options that control message delivery and content protection. These options are available in the PostPost dashboard under "Telegram Presets" when creating or editing a post with a Telegram channel selected.
Available Options
| Option | Description | API Parameter |
|---|---|---|
| Disable link preview | Prevents Telegram from generating link previews for URLs in the message | disableWebPagePreview |
| Silent notification | Sends the message without triggering a notification sound on recipients' devices | disableNotification |
| Caption above media | Places the caption above the photo/video instead of below (only applies when media is attached) | showCaptionAboveMedia |
| Protect content | Prevents recipients from forwarding, saving, or copying the message content | protectContent |
Using Post Options via API
To set Telegram-specific options via the API, include the platformSettings.telegram object in your request:
JavaScript (fetch)
const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
content: '*Exclusive Update*\n\nThis content is protected and cannot be forwarded.',
platforms: ['telegram-1001234567890'],
platformSettings: {
telegram: {
disableNotification: true, // Send silently
disableWebPagePreview: true, // No link previews
showCaptionAboveMedia: false, // Caption below media (default)
protectContent: true // Prevent forwarding/saving
}
}
})
});
const data = await response.json();
console.log(data);
// Response: { "success": true, "postGroupId": "abc123..." }Python (requests)
import requests
response = requests.post(
'https://api.postpost.dev/api/v1/create-post',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'content': '*Exclusive Update*\n\nThis content is protected and cannot be forwarded.',
'platforms': ['telegram-1001234567890'],
'platformSettings': {
'telegram': {
'disableNotification': True,
'disableWebPagePreview': True,
'showCaptionAboveMedia': False,
'protectContent': True
}
}
}
)
data = response.json()
print(data)
# Response: { "success": true, "postGroupId": "abc123..." }Option Details
Disable Link Preview (disableWebPagePreview)
When enabled, Telegram will not generate preview cards for URLs in your message. Useful for:
- Keeping messages compact
- Avoiding preview images that may not represent your content well
- Reducing visual clutter in channels with frequent link sharing
Silent Notification (disableNotification)
When enabled, recipients will receive the message without a notification sound. The message still appears in their chat list and shows an unread badge. Useful for:
- Posting during off-hours without disturbing subscribers
- High-frequency update channels
- Non-urgent announcements
Caption Above Media (showCaptionAboveMedia)
When enabled and media is attached, the caption text appears above the image/video instead of below. This option only applies when the post includes media. Useful for:
- Emphasizing the text content over the visual
- Creating a headline-style presentation
- Matching specific visual preferences
Protect Content (protectContent)
When enabled, Telegram restricts what recipients can do with your message:
- Cannot forward the message to other chats
- Cannot save media to device
- Cannot copy text (on mobile apps)
- Screenshot restrictions on some platforms
Useful for:
- Exclusive or premium content
- Time-sensitive announcements
- Content you want to keep within your channel
Note: Content protection is enforced by Telegram clients but is not 100% foolproof. Users with modified clients or screen capture tools may still be able to save content.
Examples
Post a Text Message
JavaScript (fetch)
const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
content: '*Product Update v2.5*\n\nWe have shipped the following improvements:\n\n- _Faster API response times_ (avg 45ms)\n- New `batch` endpoint for bulk operations\n- Improved error messages with `error_code` field\n\n> This update is backward compatible. No migration needed.\n\nFull changelog: [docs.example.com/changelog](https://docs.example.com/changelog)',
platforms: ['telegram-1001234567890']
})
});
const data = await response.json();
console.log(data);
// Response: { "success": true, "postGroupId": "abc123..." }Python (requests)
import requests
content = """*Product Update v2.5*
We have shipped the following improvements:
- _Faster API response times_ (avg 45ms)
- New `batch` endpoint for bulk operations
- Improved error messages with `error_code` field
> This update is backward compatible. No migration needed.
Full changelog: [docs.example.com/changelog](https://docs.example.com/changelog)"""
response = requests.post(
'https://api.postpost.dev/api/v1/create-post',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'content': content,
'platforms': ['telegram-1001234567890']
}
)
data = response.json()
print(data)
# Response: { "success": true, "postGroupId": "abc123..." }cURL
curl -X POST https://api.postpost.dev/api/v1/create-post \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"content": "*Product Update v2.5*\n\nWe have shipped the following improvements:\n\n- _Faster API response times_ (avg 45ms)\n- New `batch` endpoint for bulk operations\n- Improved error messages with `error_code` field\n\n> This update is backward compatible. No migration needed.\n\nFull changelog: [docs.example.com/changelog](https://docs.example.com/changelog)",
"platforms": ["telegram-1001234567890"]
}'
# Response: { "success": true, "postGroupId": "abc123..." }Node.js (axios)
const axios = require('axios');
const content = `*Product Update v2.5*
We have shipped the following improvements:
- _Faster API response times_ (avg 45ms)
- New \`batch\` endpoint for bulk operations
- Improved error messages with \`error_code\` field
> This update is backward compatible. No migration needed.
Full changelog: [docs.example.com/changelog](https://docs.example.com/changelog)`;
const response = await axios.post('https://api.postpost.dev/api/v1/create-post', {
content,
platforms: ['telegram-1001234567890']
}, {
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
}
});
console.log(response.data);
// Response: { "success": true, "postGroupId": "abc123..." }Post with an Image
JavaScript (fetch)
const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
content: '*New Dashboard Preview*\n\nHere is a sneak peek at our redesigned analytics dashboard. Key improvements include real-time data refresh and customizable widgets.',
platforms: ['telegram-1001234567890']
})
});
const data = await response.json();
console.log(data);
// Response: { "success": true, "postGroupId": "abc123..." }Python (requests)
import requests
response = requests.post(
'https://api.postpost.dev/api/v1/create-post',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'content': '*New Dashboard Preview*\n\nHere is a sneak peek at our redesigned analytics dashboard. Key improvements include real-time data refresh and customizable widgets.',
'platforms': ['telegram-1001234567890']
}
)
data = response.json()
print(data)
# Response: { "success": true, "postGroupId": "abc123..." }cURL
curl -X POST https://api.postpost.dev/api/v1/create-post \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"content": "*New Dashboard Preview*\n\nHere is a sneak peek at our redesigned analytics dashboard. Key improvements include real-time data refresh and customizable widgets.",
"platforms": ["telegram-1001234567890"]
}'
# Response: { "success": true, "postGroupId": "abc123..." }Node.js (axios)
const axios = require('axios');
const response = await axios.post('https://api.postpost.dev/api/v1/create-post', {
content: '*New Dashboard Preview*\n\nHere is a sneak peek at our redesigned analytics dashboard. Key improvements include real-time data refresh and customizable widgets.',
platforms: ['telegram-1001234567890']
}, {
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
}
});
console.log(response.data);
// Response: { "success": true, "postGroupId": "abc123..." }Note: To attach media to a Telegram post, first create the post, then upload media using the media upload workflow with the returned
postGroupId.
Post with a Video
JavaScript (fetch)
const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
content: '*Feature Demo*\n\nWatch our 60-second demo of the new collaboration tools.',
platforms: ['telegram-1001234567890']
})
});
const data = await response.json();
console.log(data);
// Response: { "success": true, "postGroupId": "abc123..." }Python (requests)
import requests
response = requests.post(
'https://api.postpost.dev/api/v1/create-post',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'content': '*Feature Demo*\n\nWatch our 60-second demo of the new collaboration tools.',
'platforms': ['telegram-1001234567890']
}
)
data = response.json()
print(data)
# Response: { "success": true, "postGroupId": "abc123..." }cURL
curl -X POST https://api.postpost.dev/api/v1/create-post \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"content": "*Feature Demo*\n\nWatch our 60-second demo of the new collaboration tools.",
"platforms": ["telegram-1001234567890"]
}'
# Response: { "success": true, "postGroupId": "abc123..." }Node.js (axios)
const axios = require('axios');
const response = await axios.post('https://api.postpost.dev/api/v1/create-post', {
content: '*Feature Demo*\n\nWatch our 60-second demo of the new collaboration tools.',
platforms: ['telegram-1001234567890']
}, {
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
}
});
console.log(response.data);
// Response: { "success": true, "postGroupId": "abc123..." }Platform Quirks
- Bot must be admin: The Telegram bot must be added as an administrator to the target channel or group with
can_post_messagespermission. The admin permission check happens at connection time, not at posting time — if the bot is not an admin withcan_post_messages, the connection will be rejected during setup. - Caption overflow behavior: When posting with media, the text is sent as a caption (1,024-character limit via bot API). If the content exceeds 1,024 characters and media is attached, the text is sent as a separate reply message to the media post rather than being truncated or rejected. Text-only messages support up to 4,096 characters via MTProto.
- Caption validation gap: PostPost's validation layer (
postValidationService.js) does not currently validate caption length for Telegram. A 1,024-character caption limit exists at the Telegram API level, but PostPost does not pre-check this. If your caption exceeds 1,024 characters on a media post, the error will come from Telegram's API at publish time, not from PostPost's validation. - WebP auto-conversion: WebP images are automatically converted to JPEG before sending to Telegram.
- Markdown formatting: Telegram supports a subset of markdown. PostPost's
safeParseMarkdownuses single asterisks for bold:*bold*,_italic_,`code`,[text](url), and> blockquote. Note that this differs from standard Markdown where**double asterisks**denote bold. Not all markdown features are supported (e.g., headers are not rendered as headers). - Mixed media types not supported: A single post cannot contain both images and videos. Attempting to send mixed media types will result in an error. Note that PostPost's backend validation does not enforce mixed media type restrictions for Telegram (it only does so for Instagram). If Telegram rejects mixed media, the error comes from the Telegram API itself, not from PostPost's validation layer.
- Bot connection media group limitations: Bot connections support either a single video OR multiple photos in a media group, but not multiple videos. Multi-video posts are not supported for bot connections. If you need to post multiple videos, create separate posts for each video.
- Channel name format: When setting up the connection, provide the channel name with the
@prefix (e.g.,@mychannel). ThechannelNamefield also accepts a numeric chat ID, which is required for private channels that do not have a public@username. - Bot token security: Your bot token is stored by PostPost in the connection record and is never exposed in API responses. Treat your bot token like a password. Bot tokens are stored in plaintext in the connection record. Encryption at rest is planned but not yet implemented. MTProto sessions, however, ARE encrypted at rest (the service user's session is stored encrypted and decrypted at runtime).
- MTProto test-connection limitation: The
test-connectionendpoint always fails for MTProto connections. The validator checksconnectionType === 'bot'before validating the bot token. MTProto connections haveconnectionType: 'mtproto', so they skip the bot validation block entirely and fall through to the default failure response with a misleading'Invalid bot token'error. This is a known limitation; MTProto connections work correctly for posting despite failing the test-connection check. - Message editing: Once posted, Telegram messages can be edited, but this capability is not currently exposed through the PostPost API.
API Limits
Understanding the difference between Bot API limits and regular user limits is critical for successful Telegram integration.
Character Limits
| Element | Limit |
|---|---|
| Text message | 4,096 characters |
| Bot caption | 1,024 characters (bots cannot get Premium 2,048 caption limit; the 4,096 limit is for text-only messages, not captions) |
| Bot username | 32 characters |
| Channel name | 128 characters |
Image Limits (Bot API)
| Property | Limit |
|---|---|
| Max size | 10 MB |
| Max count | 10 images per media group |
| Formats | JPEG, PNG, GIF, WebP, BMP |
Video Limits (Bot API)
| Property | Limit |
|---|---|
| Duration | No limit (only size matters) |
| Max size | 50 MB (NOT 4 GB - that's for regular users!) |
| Local Bot API Server | 2 GB max |
| Formats | MP4, MOV, AVI, MKV, WebM |
CRITICAL: Bot API vs User Limits
Bots have significantly lower limits than regular Telegram users. This is a common source of errors:
| Limit | Bot API | Regular Users |
|---|---|---|
| File size | 50 MB | 4 GB |
| Caption | 1,024 chars | 4,096 chars |
Common Error Messages
| Error | Cause |
|---|---|
MEDIA_CAPTION_TOO_LONG | Caption exceeds 1,024 characters (bots) |
Bad Request: file is too big | File exceeds 50 MB |
Rate Limits
| Scope | Limit |
|---|---|
| Global | 30 messages/second |
| Per group | 20 messages/minute |
Mastodon
Post to Mastodon and the Fediverse programmatically using the PostPost REST API. A simpler alternative to the official Mastodon API, Megalodon, or direct ActivityPub integration.
MCP Server
Control PostPost directly from AI assistants like Claude Code, Claude Desktop, Cursor, and any MCP-compatible client. No coding required -- just describe what you want in plain English.