Telegram
Connect a Telegram channel or group with an access code, then publish or schedule text, photo, video, and album posts through PostZen.
PostZen publishes and schedules posts to Telegram channels and groups through a shared bot, @PostZenScheduleBot. Telegram connects with a short-lived access code instead of OAuth: you add the bot as an administrator of the chat, then DM it your code.
Quick reference
| Property | Telegram via PostZen |
|---|---|
| Platform value | telegram |
| Authentication | Access code (PZ-XXXXXX) sent to @PostZenScheduleBot; no OAuth |
| Chat types | Channels, groups, and supergroups |
| Post types | Text, photo, video, album, GIF |
| Character limit | 4,096 characters for a text-only post |
| Caption limit | 1,024 characters when the post has any media |
| Media per post | 1–10 items |
| Maximum photo size | 10 MB per photo |
| Maximum video size | 50 MB per video |
| Mixing photos and video | Allowed in a single album |
| GIFs | Supported, but must be posted on their own |
| Formatting | Plain text by default; optional html or markdownv2 |
| Scheduling | Supported |
| Analytics | Not available — Telegram's Bot API reports no metrics |
Before you start
You need a PostZen profile and a Telegram channel or group you can administer. PostZen uses one shared bot, so there is no Telegram developer app to register and no bot token to manage.
@PostZenScheduleBot must be an administrator of the chat before you connect it. In a channel it also needs the Post Messages permission. PostZen checks these rights during connect and refuses to save a connection it cannot publish through.
Who the post appears to come from depends on the chat type:
- In a channel, posts appear as the channel itself. Readers never see the bot.
- In a group or supergroup, posts appear as @PostZenScheduleBot.
Keep these publishing limits in mind:
- A text-only post allows 4,096 characters. The moment you attach media, the same text becomes a caption and is capped at 1,024 characters.
- A post can carry 1–10 media items. Photos must be 10 MB or smaller and videos 50 MB or smaller.
- A GIF cannot go in an album. Post it on its own.
- Telegram does not accept audio files or documents through PostZen.
Media URLs must be publicly accessible direct links to the files. Google Drive, Dropbox, OneDrive, and iCloud share links return HTML pages instead of files. Use a direct URL or upload the file through POST /v1/media/presign.
The free tier allows 2 connected accounts before a payment method is required. Connecting another account returns a 402.
Connect your account
From the dashboard
PostZen mints a single-use access code in the format PZ-XXXXXX that expires after 15 minutes. Complete the handshake in Telegram:
Add the bot as an administrator. Open your channel or group, go to Administrators, and add @PostZenScheduleBot. In a channel, enable Post Messages.
DM the bot your code. Open a chat with @PostZenScheduleBot and send the code together with your channel's public username, for example PZ-ABC123 @yourchannel.
For a private channel, forward instead. Send the code, then forward any message from the channel you want to connect. The two halves may arrive in either order and in separate messages — the bot remembers whichever it received first.
For a private group, post the code inside the group. Forwarded group messages don't identify their source chat, so send the code as a normal message in the group itself — the bot is already a member and completes the handshake from there.
The bot replies in the DM either way. On success it confirms the chat by name, and the connection appears in PostZen immediately. If the bot is missing rights, it says exactly which permission to grant and you can send the code again.
Whoever sends the code must be an administrator of the chat being connected. The code identifies your PostZen account; your admin role is what authorizes connecting that chat.
From the API
Start the connection with GET /v1/connect/telegram?profileId=.... PostZen returns { authUrl, state }; the state expires after 10 minutes.
const { data } = await postzen.connect.createConnectUrl({
path: { platform: 'telegram' },
query: { profileId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e' },
});
console.log(data.authUrl); // open this PostZen-hosted page
console.log(data.state); // expires after 10 minutesresponse = client.connect.create_connect_url(
"telegram",
profile_id="jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
)
print(response.authUrl) # open this PostZen-hosted page
print(response.state) # expires after 10 minutescurl "https://api.postzen.dev/v1/connect/telegram?profileId=jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e" \
-H "Authorization: Bearer $POSTZEN_API_KEY"Send the user to the returned authUrl. The URL opens PostZen's hosted Telegram connection page, which mints the access code and walks the user through adding the bot. There is no Telegram authorization screen and no OAuth grant for this integration — the connection is created by the bot once the user DMs the code, not by a callback to your app.
The hosted page updates live as the handshake completes, then returns the user to your redirectUrl with connected=telegram&status=connected.
Quick start
Create a text post by targeting the connected chat with the telegram platform value. The post below publishes immediately.
const { data } = await postzen.posts.createPost({
body: {
content: 'Hello from Telegram!',
publishNow: true,
platforms: [
{
platform: 'telegram',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
},
],
},
});
console.log(data.post._id);response = client.posts.create_post(
content="Hello from Telegram!",
publish_now=True,
platforms=[
{
"platform": "telegram",
"account_id": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
},
],
)
print(response.post.field_id)curl -X POST https://api.postzen.dev/v1/posts \
-H "Authorization: Bearer $POSTZEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Hello from Telegram!",
"publishNow": true,
"platforms": [
{
"platform": "telegram",
"accountId": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e"
}
]
}'Set exactly one of publishNow, scheduledFor, or isDraft. For a scheduled post, replace publishNow with an ISO-8601 scheduledFor value at least 60 seconds in the future. Telegram has no native scheduling in this flow: PostZen holds the post and the bot sends it at publish time.
Content types
Text posts
A post with no media can contain up to 4,096 characters. For cross-posts, use customContent on the Telegram target when the shared text needs a different length or different formatting:
{
platform: 'telegram',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
customContent: 'A Telegram-specific version of the announcement.',
}Photo posts
Attach one photo through mediaItems. content becomes the caption and is limited to 1,024 characters.
Video posts
Attach one video the same way. Videos must be 50 MB or smaller — PostZen downloads the file and uploads the bytes to Telegram, so the limit applies to the actual file, not to what your CDN reports.
Albums
Two to ten items publish as a Telegram media group. Photos and videos may be mixed freely in one album. Telegram renders the first item's caption as the album caption, which is what PostZen sets.
const { data } = await postzen.posts.createPost({
body: {
content: 'Three shots from the launch event.',
publishNow: true,
mediaItems: [
{ url: 'https://cdn.example.com/images/stage.jpg' },
{ url: 'https://cdn.example.com/images/crowd.jpg' },
{ url: 'https://cdn.example.com/videos/keynote.mp4' },
],
platforms: [
{
platform: 'telegram',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
},
],
},
});
console.log(data.post._id);response = client.posts.create_post(
content="Three shots from the launch event.",
publish_now=True,
media_items=[
{"url": "https://cdn.example.com/images/stage.jpg"},
{"url": "https://cdn.example.com/images/crowd.jpg"},
{"url": "https://cdn.example.com/videos/keynote.mp4"},
],
platforms=[
{
"platform": "telegram",
"account_id": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
},
],
)
print(response.post.field_id)curl -X POST https://api.postzen.dev/v1/posts \
-H "Authorization: Bearer $POSTZEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Three shots from the launch event.",
"publishNow": true,
"mediaItems": [
{ "url": "https://cdn.example.com/images/stage.jpg" },
{ "url": "https://cdn.example.com/images/crowd.jpg" },
{ "url": "https://cdn.example.com/videos/keynote.mp4" }
],
"platforms": [
{
"platform": "telegram",
"accountId": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e"
}
]
}'GIFs
A GIF publishes as a Telegram animation. Telegram has no album form for animations, so a GIF must be the only media item in the post. Including a GIF alongside anything else is rejected before publishing.
Formatting
By default PostZen sends Telegram text as plain text. This is deliberate: with a parse mode enabled, a single stray _ or * anywhere in your copy makes Telegram reject the entire message.
Set settings.parseMode when you want formatting.
HTML — recommended
parseMode: 'html' is the safer of the two modes. Only <, >, and & need escaping (as <, >, and &), and everything else in your copy passes through untouched.
Telegram supports a small tag set: <b>, <i>, <u>, <s>, <a href="...">, <code>, <pre>, <blockquote>, and <tg-spoiler>.
{
platform: 'telegram',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
customContent: '<b>Release 2.4</b> is out. <a href="https://example.com/notes">Read the notes</a>.',
settings: {
parseMode: 'html',
},
}MarkdownV2
MarkdownV2 requires you to escape every occurrence of _ * [ ] ( ) ~ ` > # + - = | { } . ! with a preceding backslash, including inside ordinary prose. An unescaped period or hyphen makes Telegram reject the whole message, and the post fails with a validation error.
MarkdownV2 is offered for callers that already generate escaped Telegram markup. If you are writing copy by hand, use html instead.
{
"platform": "telegram",
"accountId": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
"customContent": "*Release 2\\.4* is out\\. Read the notes\\!",
"settings": {
"parseMode": "markdownv2"
}
}Formatting counts against the same limits as plain text: markup characters are part of the 4,096-character message and the 1,024-character caption.
Media requirements
Photos
| Requirement | Value |
|---|---|
| Photos per post | 1–10, counted with videos against the same 10-item ceiling |
| Maximum file size | 10 MB per photo |
| PostZen media upload types | JPEG/JPG, PNG, WebP, GIF |
| Media source | Publicly accessible direct URL, or a publicUrl returned by /v1/media/presign |
| Alt text | Not supported — Telegram has no alt-text field |
Videos
| Requirement | Value |
|---|---|
| Videos per post | 1–10, counted with photos against the same 10-item ceiling |
| Maximum file size | 50 MB per video |
| Recommended format | MP4 (H.264 video, AAC audio) |
| Duration | No PostZen limit |
GIFs
| Requirement | Value |
|---|---|
| GIFs per post | Exactly 1, and nothing else |
| Maximum file size | 50 MB — a GIF is sent as an animation and shares the video limit |
| Album support | Not supported |
PostZen downloads every file and uploads the bytes to Telegram rather than handing Telegram a URL. Telegram's own fetcher caps remote photos at 5 MB and remote video at 20 MB; uploading the bytes is what lets PostZen honor the higher 10 MB and 50 MB limits.
Audio files and documents are rejected at validation. Telegram posts through PostZen support images, GIFs, and videos only.
Platform settings
Place Telegram settings in the target object's settings field. All four are optional.
| Key | Type | Notes |
|---|---|---|
parseMode | 'html' | 'markdownv2' | Formatting mode for the message or caption. Omit for plain text, which is the default. |
disableNotification | boolean | When true, members receive the post silently — no sound or vibration. |
disableLinkPreview | boolean | When true, suppresses the link preview card for URLs in the text. Applies to text-only posts; a post with media has no link preview to suppress. |
protectContent | boolean | When true, Telegram blocks forwarding and saving of the post. |
{
platform: 'telegram',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
settings: {
parseMode: 'html',
disableNotification: true,
disableLinkPreview: true,
protectContent: false,
},
}Snake_case aliases are accepted as well, so parse_mode, disable_notification, disable_link_preview, and protect_content all work. silent is accepted as an alias for disableNotification, and disableWebPagePreview for disableLinkPreview.
What you can't do
- Read analytics or insights. Telegram's Bot API exposes no view, impression, or reach metrics for a post, and no follower or subscriber counts. This is a Bot API limitation, not a rollout gap — per-message view counts exist only inside the Telegram client for channel admins.
- Delete a published post. Telegram only allows a message to be deleted within 48 hours of posting, and PostZen does not delete Telegram messages remotely. Deleting a post in PostZen removes the PostZen record only; the message stays in the channel. Delete it in Telegram itself if you need it gone.
- Edit a published post.
- Create polls or quizzes.
- Pin a post to the top of a channel or group.
- Post documents, files, or audio.
- Post to a private chat with an individual, or read or send DMs.
- Add alt text to media.
- Use OAuth. Telegram connects with an access code and an admin-rights check.
Common errors
| Error | Cause | Fix |
|---|---|---|
| Bot is not an administrator | @PostZenScheduleBot was never made an admin, or a channel admin exists without Post Messages. | Open the chat's Administrators list, add or edit @PostZenScheduleBot, enable Post Messages for channels, then send your code again. |
| Bot was kicked / not enough rights | The bot lost admin rights or was removed after connecting. The account flips to needs reauthorization and publishing stops. | Re-add @PostZenScheduleBot as an administrator. The account recovers automatically once rights are restored. |
| Chat not found | The connection no longer points at a reachable chat — the channel was deleted, or the @username was wrong at connect time. | Reconnect the chat in PostZen. |
| Caption exceeds 1,024 characters | The post has media, so content is a caption and the tighter limit applies. | Shorten content, set a shorter customContent on the Telegram target, or publish the text without media to use the 4,096-character limit. |
| Text exceeds 4,096 characters | Telegram's hard ceiling for a single message. | Shorten content or set customContent on the Telegram target. |
| Media exceeds 10 MB / 50 MB | A photo is over 10 MB, or a video or GIF is over 50 MB. | Compress the file before posting. |
| GIF in an album | A GIF was sent alongside other media. Telegram has no album form for animations. | Post the GIF as the only media item. |
| Invalid HTML or MarkdownV2 | An unclosed tag, an unsupported tag, or an unescaped MarkdownV2 special character. | Escape <, >, and & for HTML; escape every MarkdownV2 special character; or drop parseMode to send plain text. |
| Rate limited | Telegram applies a flood wait to the bot for this chat. | Nothing to do. PostZen retries automatically after the retry_after interval Telegram returns. |
| Access code invalid or expired | Codes are single-use and expire after 15 minutes. | Generate a fresh code in PostZen and send it again. |
402 while connecting | Your PostZen account has reached the free-tier limit of 2 connected accounts without a payment method. | Add a payment method before connecting another account. |
A basic group that Telegram upgrades to a supergroup gets a brand-new chat id. PostZen detects this, updates the stored chat, and retries the publish — no action needed.