PostZen

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

PropertyTelegram via PostZen
Platform valuetelegram
AuthenticationAccess code (PZ-XXXXXX) sent to @PostZenScheduleBot; no OAuth
Chat typesChannels, groups, and supergroups
Post typesText, photo, video, album, GIF
Character limit4,096 characters for a text-only post
Caption limit1,024 characters when the post has any media
Media per post1–10 items
Maximum photo size10 MB per photo
Maximum video size50 MB per video
Mixing photos and videoAllowed in a single album
GIFsSupported, but must be posted on their own
FormattingPlain text by default; optional html or markdownv2
SchedulingSupported
AnalyticsNot 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 minutes
response = client.connect.create_connect_url(
    "telegram",
    profile_id="jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
)

print(response.authUrl)  # open this PostZen-hosted page
print(response.state)    # expires after 10 minutes
curl "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.

parseMode: 'html' is the safer of the two modes. Only <, >, and & need escaping (as &lt;, &gt;, and &amp;), 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

RequirementValue
Photos per post1–10, counted with videos against the same 10-item ceiling
Maximum file size10 MB per photo
PostZen media upload typesJPEG/JPG, PNG, WebP, GIF
Media sourcePublicly accessible direct URL, or a publicUrl returned by /v1/media/presign
Alt textNot supported — Telegram has no alt-text field

Videos

RequirementValue
Videos per post1–10, counted with photos against the same 10-item ceiling
Maximum file size50 MB per video
Recommended formatMP4 (H.264 video, AAC audio)
DurationNo PostZen limit

GIFs

RequirementValue
GIFs per postExactly 1, and nothing else
Maximum file size50 MB — a GIF is sent as an animation and shares the video limit
Album supportNot 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.

KeyTypeNotes
parseMode'html' | 'markdownv2'Formatting mode for the message or caption. Omit for plain text, which is the default.
disableNotificationbooleanWhen true, members receive the post silently — no sound or vibration.
disableLinkPreviewbooleanWhen 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.
protectContentbooleanWhen 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

ErrorCauseFix
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 rightsThe 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 foundThe 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 charactersThe 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 charactersTelegram's hard ceiling for a single message.Shorten content or set customContent on the Telegram target.
Media exceeds 10 MB / 50 MBA photo is over 10 MB, or a video or GIF is over 50 MB.Compress the file before posting.
GIF in an albumA GIF was sent alongside other media. Telegram has no album form for animations.Post the GIF as the only media item.
Invalid HTML or MarkdownV2An 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 limitedTelegram 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 expiredCodes are single-use and expire after 15 minutes.Generate a fresh code in PostZen and send it again.
402 while connectingYour 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.

On this page