LateLate API
Platforms

Telegram API

Post to Telegram channels and groups with Late API - Text, images, videos, and media albums


Quick Start

Post to a Telegram channel or group:

curl -X POST https://getlate.dev/api/v1/posts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Hello from Late API! Check out our latest update.",
    "platforms": [
      {"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
    ],
    "publishNow": true
  }'
const response = await fetch('https://getlate.dev/api/v1/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    content: 'Hello from Late API! Check out our latest update.',
    platforms: [
      { platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
    ],
    publishNow: true
  })
});

const { post } = await response.json();
console.log('Posted to Telegram!', post._id);
import requests

response = requests.post(
    'https://getlate.dev/api/v1/posts',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'content': 'Hello from Late API! Check out our latest update.',
        'platforms': [
            {'platform': 'telegram', 'accountId': 'YOUR_ACCOUNT_ID'}
        ],
        'publishNow': True
    }
)

post = response.json()
print(f"Posted to Telegram! {post['post']['_id']}")

Connect a Telegram Account

Late provides a managed bot (@LateScheduleBot) for Telegram integration. No need to create your own bot - just add Late's bot to your channel or group.

This is the easiest way to connect a Telegram channel or group.

Step 1: Generate an Access Code

curl -X GET "https://getlate.dev/api/v1/connect/telegram?profileId=YOUR_PROFILE_ID" \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch(
  'https://getlate.dev/api/v1/connect/telegram?profileId=YOUR_PROFILE_ID',
  {
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
  }
);

const { code, botUsername, instructions } = await response.json();
console.log(`Your access code: ${code}`);
console.log(`Bot to message: @${botUsername}`);
response = requests.get(
    'https://getlate.dev/api/v1/connect/telegram',
    params={'profileId': 'YOUR_PROFILE_ID'},
    headers={'Authorization': 'Bearer YOUR_API_KEY'}
)

data = response.json()
print(f"Your access code: {data['code']}")
print(f"Bot to message: @{data['botUsername']}")

Response:

{
  "code": "LATE-ABC123",
  "expiresAt": "2025-01-15T12:30:00.000Z",
  "expiresIn": 900,
  "botUsername": "LateScheduleBot",
  "instructions": [
    "1. Add @LateScheduleBot as an administrator in your channel/group",
    "2. Open a private chat with @LateScheduleBot",
    "3. Send: LATE-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:

  1. Go to your channel settings
  2. Add @LateScheduleBot as an Administrator
  3. Grant permission to Post Messages

For Groups:

  1. Add @LateScheduleBot to the group
  2. Make the bot an Administrator (required for posting)

Step 3: Send the Access Code

  1. Open a private chat with @LateScheduleBot
  2. Send your access code with your channel: LATE-ABC123 @yourchannel
  3. 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

curl -X PATCH "https://getlate.dev/api/v1/connect/telegram?code=LATE-ABC123" \
  -H "Authorization: Bearer YOUR_API_KEY"
// Poll every 3 seconds until connected
const checkStatus = async (code) => {
  const response = await fetch(
    `https://getlate.dev/api/v1/connect/telegram?code=${code}`,
    {
      method: 'PATCH',
      headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
    }
  );
  return response.json();
};

// Example polling loop
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.');
    }

    // Wait 3 seconds before next check
    await new Promise(resolve => setTimeout(resolve, 3000));
  }
};
import time

def check_status(code):
    response = requests.patch(
        'https://getlate.dev/api/v1/connect/telegram',
        params={'code': code},
        headers={'Authorization': 'Bearer YOUR_API_KEY'}
    )
    return response.json()

# Poll until connected
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)  # Wait 3 seconds

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 Late bot is already an administrator in your channel/group:

curl -X POST https://getlate.dev/api/v1/connect/telegram \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "YOUR_PROFILE_ID",
    "chatId": "-1001234567890"
  }'
const response = await fetch('https://getlate.dev/api/v1/connect/telegram', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    profileId: 'YOUR_PROFILE_ID',
    chatId: '-1001234567890'  // or '@mychannel' for public channels
  })
});

const { account } = await response.json();
console.log('Connected:', account._id);
response = requests.post(
    'https://getlate.dev/api/v1/connect/telegram',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'profileId': 'YOUR_PROFILE_ID',
        'chatId': '-1001234567890'  # or '@mychannel' for public channels
    }
)

data = response.json()
print(f"Connected: {data['account']['_id']}")

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

Overview

Telegram supports text messages, images, videos, and mixed media albums. Posts can be sent to channels or groups where the Late bot has posting permissions.

FeatureSupport
Text postsUp to 4096 characters
Media captionsUp to 1024 characters
ImagesUp to 10 per album
VideosUp to 10 per album
Mixed mediaImages and videos in same album
SchedulingYes
AnalyticsNot available (platform limitation)

Media Requirements

Images

PropertyRequirement
Max Images10 per album
FormatsJPEG, PNG, GIF, WebP
Max File Size10 MB
Max Resolution10000 × 10000 px

Videos

PropertyRequirement
Max Videos10 per album
FormatsMP4, MOV
Max File Size50 MB
Max DurationNo limit
CodecH.264 recommended

Platform-Specific Options

Telegram supports several message options:

curl -X POST https://getlate.dev/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": false,
        "protectContent": false
      }
    }],
    "publishNow": true
  }'
const response = await fetch('https://getlate.dev/api/v1/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    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: false,
        protectContent: false
      }
    }],
    publishNow: true
  })
});
response = requests.post(
    'https://getlate.dev/api/v1/posts',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        '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': False,
                'protectContent': False
            }
        }],
        'publishNow': True
    }
)

Available Options

OptionTypeDefaultDescription
parseModestringHTMLText formatting mode: HTML, Markdown, or MarkdownV2
disableWebPagePreviewbooleanfalseDisable link preview generation for URLs
disableNotificationbooleanfalseSend message silently (no notification sound)
protectContentbooleanfalsePrevent message from being forwarded or saved

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: _, *, [, ], (, ), ~, `, >, #, +, -, =, |, {, }, ., !

Posting with Media

Single Image

curl -X POST https://getlate.dev/api/v1/posts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Check out this photo!",
    "mediaItems": [
      {"url": "https://example.com/image.jpg"}
    ],
    "platforms": [
      {"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
    ],
    "publishNow": true
  }'
const response = await fetch('https://getlate.dev/api/v1/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    content: 'Check out this photo!',
    mediaItems: [
      { url: 'https://example.com/image.jpg' }
    ],
    platforms: [
      { platform: 'telegram', accountId: 'YOUR_ACCOUNT_ID' }
    ],
    publishNow: true
  })
});
response = requests.post(
    'https://getlate.dev/api/v1/posts',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'content': 'Check out this photo!',
        'mediaItems': [
            {'url': 'https://example.com/image.jpg'}
        ],
        'platforms': [
            {'platform': 'telegram', 'accountId': 'YOUR_ACCOUNT_ID'}
        ],
        'publishNow': True
    }
)

Media Album (Multiple Images/Videos)

{
  "content": "Our latest product gallery!",
  "mediaItems": [
    {"url": "https://example.com/image1.jpg"},
    {"url": "https://example.com/image2.jpg"},
    {"url": "https://example.com/video.mp4"},
    {"url": "https://example.com/image3.jpg"}
  ],
  "platforms": [
    {"platform": "telegram", "accountId": "YOUR_ACCOUNT_ID"}
  ],
  "publishNow": true
}

Note: Media albums support up to 10 items. Images and videos can be mixed in the same album.

Channel vs Group Posts

DestinationAuthor Display
ChannelChannel name and logo
GroupBot name (LateScheduleBot)

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 Late bot.

Character Limits

Content TypeLimit
Text-only messages4096 characters
Media captions1024 characters

Silent Messages

Send messages without triggering notification sounds:

{
  "content": "Late night update - didn't want to wake anyone!",
  "platforms": [{
    "platform": "telegram",
    "accountId": "YOUR_ACCOUNT_ID",
    "platformSpecificData": {
      "disableNotification": true
    }
  }]
}

Protected Content

Prevent users from forwarding or saving your content:

{
  "content": "Exclusive content for channel members only!",
  "platforms": [{
    "platform": "telegram",
    "accountId": "YOUR_ACCOUNT_ID",
    "platformSpecificData": {
      "protectContent": true
    }
  }]
}

Analytics Limitations

Important: Telegram analytics are not available via API. The Telegram Bot API does not expose message analytics (views, forwards, reactions).

  • View counts are only visible to channel admins directly in the Telegram app
  • This is a Telegram platform limitation that affects all third-party tools
  • Message IDs are returned for tracking purposes

Common Issues

"Bot is not a member of the channel"

  • Ensure @LateScheduleBot is added to the channel/group as an administrator
  • Grant the bot permission to post messages

"Message is too long"

  • Text-only messages: max 4096 characters
  • Media captions: max 1024 characters
  • Split long content into multiple messages

"Wrong file identifier/HTTP URL specified"

  • Ensure media URLs are publicly accessible
  • Use HTTPS URLs
  • Check that the URL directly points to the file (no redirects)

"Can't parse entities"

  • Check your HTML/Markdown syntax
  • Ensure special characters are properly escaped in MarkdownV2
  • Verify all tags are properly closed in HTML mode

Media not displaying

  • Verify file format is supported
  • Check file size limits (10 MB for images, 50 MB for videos)
  • Ensure the URL is publicly accessible without authentication

"Access code expired"

  • Access codes are valid for 15 minutes
  • Generate a new code with GET /v1/connect/telegram