# Telegram

Coming soon. Connect a Telegram channel or group with an access code, publish text, photos, videos, documents and albums, edit messages, and run bot DMs and commands.

> **Telegram is coming soon:**
> 
> Telegram accounts cannot be connected yet. [`GET /v1/connect/telegram`](https://pozy.ai/docs/api/getConnectUrl) and the Telegram access-code endpoints answer `403` with `code: "feature_not_available"`. The rest of this page describes how Telegram will work once it opens, so you can plan for it. Watch the [changelog](https://pozy.ai/docs/changelog) for the launch.

Telegram publishing goes through a bot that is an administrator of your channel or group. There is no OAuth: you connect with a short access code, then publish with `POST /v1/posts` using the platform id `telegram`. The same bot handles direct messages in the [Inbox](https://pozy.ai/docs/inbox) and the "/" command menu.

## What you will be able to do

| Feature | Supported | Where |
| --- | --- | --- |
| Text messages with HTML or Markdown formatting | Yes | [Post types](#post-types) |
| Photo, video and document messages | Yes | [Post types](#post-types) |
| Albums, images and videos mixed | Up to 10 items | [Post types](#post-types) |
| Silent and protected messages | Yes | [Platform fields](#platform-fields) |
| Scheduling | Yes | [Scheduling](https://pozy.ai/docs/publishing/scheduling) |
| Edit a published message | Text or caption | [Editing](https://pozy.ai/docs/publishing/editing) |
| DMs with the bot | Yes, with attachments and keyboards | [Inbox](#inbox) |
| Bot command menu | Up to 100 commands | [Bot commands](#bot-commands) |
| Comments, analytics | No | Not exposed by Telegram's Bot API |

## Connect

> **Note:**
> 
> Not available yet: these steps return `403 feature_not_available` until Telegram opens.

The bot must be an administrator of the channel or group, with permission to post messages, before you connect. A bot that is a plain member, or an admin without the post permission, is the most common setup failure: every post then fails with "Bot is not a member of the channel".

### With an access code

### Generate a code

Call [Generate Telegram code](https://pozy.ai/docs/api/getTelegramConnectStatus) with the profile that should own the account. The code is valid for 15 minutes.

```bash cURL
curl "https://api.pozy.ai/v1/connect/telegram?profileId=66a1f0c2a4b9d3e8f1a2b3c4" \
  -H "Authorization: Bearer $POZY_API_KEY"
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/connect/telegram?profileId=66a1f0c2a4b9d3e8f1a2b3c4", {
  headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.code, data.botUsername, data.instructions);
```
```python Python
import os, requests

resp = requests.get(
    "https://api.pozy.ai/v1/connect/telegram",
    headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
    params={"profileId": "66a1f0c2a4b9d3e8f1a2b3c4"},
)
data = resp.json()
print(data["code"], data["botUsername"], data["instructions"])
```

The response has `code`, `expiresAt`, `expiresIn`, `botUsername` and `instructions`. Show the user the bot's username and the instructions exactly as returned.

### The user sets up the bot

In Telegram, the user:

1. Adds the bot (`botUsername`) to the channel as an administrator with the Post Messages permission, or to the group as an administrator.
2. Opens a private chat with the bot.
3. Sends the code followed by the channel username, for example `<code> @acmenews`. For a private channel with no username, they forward any message from the channel to the bot together with the code.

### Poll until connected

Call [Check Telegram status](https://pozy.ai/docs/api/completeTelegramConnect) with the code every few seconds. `status` is `pending` until the bot receives the code, then `connected` with the new account, or `expired` after 15 minutes.

```bash
curl -X PATCH "https://api.pozy.ai/v1/connect/telegram?code=$CODE" \
  -H "Authorization: Bearer $POZY_API_KEY"
```

`account._id` in the `connected` response is the `accountId` for every call that follows. If the code expires, generate a new one.

### Directly with a chat id

If the bot is already an administrator and you know the chat id, skip the code and call [Connect Telegram directly](https://pozy.ai/docs/api/initiateTelegramConnect):

```bash
curl -X POST https://api.pozy.ai/v1/connect/telegram \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "chatId": "@acmenews", "profileId": "66a1f0c2a4b9d3e8f1a2b3c4" }'
```

`chatId` is `@username` for a public channel. For a private channel or a group it is the numeric id; private channel ids start with `-100`, group ids are negative. One way to find a numeric id is to forward a message from the channel to an id-lookup bot in Telegram.

In a channel, posts appear under the channel's name and logo. In a group, they appear as sent by the bot.

## Post types

The media decides the message type:

| `mediaItems` | Result | Text used as |
| --- | --- | --- |
| None | Text message | Message body, up to 4,096 characters |
| 1 image, video or document | Photo, video or document message | Caption, up to 1,024 characters |
| 2 to 10 items | Album (images and videos can mix) | Caption on the first item |

```bash cURL
curl -X POST https://api.pozy.ai/v1/posts \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "<b>Release 2.4</b> is out.\nRead the notes: <a href=\"https://example.com/changelog\">changelog</a>",
    "platforms": [{
      "platform": "telegram",
      "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
      "platformSpecificData": { "parseMode": "HTML", "disableNotification": true }
    }],
    "publishNow": true
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    content: '<b>Release 2.4</b> is out.\nRead the notes: <a href="https://example.com/changelog">changelog</a>',
    platforms: [{
      platform: "telegram",
      accountId: "66b2e19d8c3f5a7e9d0b1c2d",
      platformSpecificData: { parseMode: "HTML", disableNotification: true },
    }],
    publishNow: true,
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.post.platforms[0].status);
```
```python Python
resp = requests.post(
    "https://api.pozy.ai/v1/posts",
    headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
    json={
        "content": '<b>Release 2.4</b> is out.\nRead the notes: <a href="https://example.com/changelog">changelog</a>',
        "platforms": [{
            "platform": "telegram",
            "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
            "platformSpecificData": {"parseMode": "HTML", "disableNotification": True},
        }],
        "publishNow": True,
    },
)
print(resp.json()["post"]["platforms"][0]["status"])
```

### Formatting

`parseMode` sets how Telegram reads `content`. HTML is the default.

| `parseMode` | Syntax |
| --- | --- |
| `HTML` | `<b>`, `<i>`, `<u>`, `<s>`, `<code>`, `<pre>`, `<a href="...">` |
| `Markdown` | `*bold*`, `_italic_`, `[link](https://...)`, backtick code |
| `MarkdownV2` | Adds `__underline__`, `~strikethrough~` and `\|\|spoiler\|\|`, but every `_ * [ ] ( ) ~ > # + - = \| { } . !` and backtick must be escaped with a backslash |

### Platform fields

| Field | Type | Notes |
| --- | --- | --- |
| `parseMode` | `HTML`, `Markdown` or `MarkdownV2` | Default `HTML` |
| `disableWebPagePreview` | boolean | No link preview |
| `disableNotification` | boolean | Deliver silently |
| `protectContent` | boolean | Recipients cannot forward or save the message |

Edit the text or caption of a published message with [Edit published post](https://pozy.ai/docs/api/editPost). The media cannot be changed.

## Media requirements

| Images | Requirement |
| --- | --- |
| Per album | Up to 10 |
| Formats | JPEG, PNG, GIF, WebP |
| Max size | 10 MB. Larger images are compressed |
| Max resolution | Width plus height up to 10,000 px. Larger images are downscaled |

| Videos | Requirement |
| --- | --- |
| Per album | Up to 10 |
| Formats | MP4, MOV (H.264 recommended) |
| Max size | 50 MB. Larger videos are compressed, up to a source size of 200 MB. Above that the file goes through untouched and Telegram refuses it |
| Duration | No limit |

URLs must be direct HTTPS links with no redirects. Telegram rejects HTTP and redirecting links with "Wrong file identifier/HTTP URL specified". [Media](https://pozy.ai/docs/publishing/media) gives you URLs that qualify.

## Limits

| Limit | Value |
| --- | --- |
| Text message | 4,096 characters |
| Caption | 1,024 characters |
| Album | 10 items |
| Bot commands | 100, names up to 32 characters (`a-z`, `0-9`, `_`, no slash), descriptions up to 256 |

## Analytics

Telegram's Bot API exposes no view or engagement counts, so Telegram has no analytics in Pozy.

## Inbox

People who message the bot show up in the [Inbox](https://pozy.ai/docs/inbox/messages).

| Feature | Supported |
| --- | --- |
| List and read conversations | Yes |
| Send text | Yes |
| Send images, videos, documents | Yes. Images up to 10 MB, videos and documents up to 50 MB |
| Edit sent messages | Text and inline keyboard |
| Inline keyboards | Buttons with callback data or URLs |
| Reply keyboards | One-time custom keyboards |
| Reply to a specific message | `replyTo` with the message id |
| Archive and unarchive | Yes |
| Read receipts, deletions | No. The Bot API does not report them |

When someone taps an inline keyboard button, the callback data arrives on the incoming message in `metadata.callbackData`. Reactions arrive as `reaction.received` when the bot is an admin of the chat; reactions in private chats are not delivered.

### Bot commands

Bot commands are the entries in the "/" menu people see when they chat with the bot. Manage them with [Get](https://pozy.ai/docs/api/getTelegramCommands), [Set](https://pozy.ai/docs/api/setTelegramCommands) and [Delete](https://pozy.ai/docs/api/deleteTelegramCommands) TG bot commands.

```bash
curl -X PUT https://api.pozy.ai/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/telegram-commands \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "commands": [{ "command": "help", "description": "How to reach support" }, { "command": "status", "description": "Check your order status" }] }'
```

See [Conversation starters](https://pozy.ai/docs/automations/conversation-starters) for menus and starters on other channels.

## Errors you may see

| Error | Cause | Fix |
| --- | --- | --- |
| "Bot is not a member of the channel" | The bot is not an admin, or lacks the post permission | Make it an administrator with Post Messages, then retry |
| `expired` on the status check | The code was not used within 15 minutes | Generate a new code |
| "Wrong file identifier/HTTP URL specified" | Media URL is HTTP, redirects or is not public | Use a direct HTTPS URL or upload through Media |
| Message too long | Text over 4,096 or caption over 1,024 characters | Shorten it, or send the text as its own message |
| Formatting error | Unescaped characters in `MarkdownV2`, or broken HTML | Escape the characters, or switch to `HTML` |

[Errors](https://pozy.ai/docs/getting-started/errors) covers the error format.

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/connect/telegram`](https://pozy.ai/docs/api/getTelegramConnectStatus) | Generate Telegram code (not available yet) |
| [`PATCH /v1/connect/telegram`](https://pozy.ai/docs/api/completeTelegramConnect) | Check Telegram status (not available yet) |
| [`POST /v1/connect/telegram`](https://pozy.ai/docs/api/initiateTelegramConnect) | Connect Telegram directly (not available yet) |
| [`GET /v1/accounts/{accountId}/telegram-commands`](https://pozy.ai/docs/api/getTelegramCommands) | Get TG bot commands |
| [`PUT /v1/accounts/{accountId}/telegram-commands`](https://pozy.ai/docs/api/setTelegramCommands) | Set TG bot commands |
| [`DELETE /v1/accounts/{accountId}/telegram-commands`](https://pozy.ai/docs/api/deleteTelegramCommands) | Delete TG bot commands |
| [`POST /v1/posts`](https://pozy.ai/docs/api/createPost) | Create post |
| [`POST /v1/posts/{postId}/edit`](https://pozy.ai/docs/api/editPost) | Edit published post |
| [`GET /v1/inbox/conversations`](https://pozy.ai/docs/api/listInboxConversations) | List conversations |
| [`POST /v1/inbox/conversations/{conversationId}/messages`](https://pozy.ai/docs/api/sendInboxMessage) | Send message |

## Webhook events

| Event | When it fires |
| --- | --- |
| [`post.published`](https://pozy.ai/docs/webhooks/events#post-published) | Post published. |
| [`post.failed`](https://pozy.ai/docs/webhooks/events#post-failed) | Post failed. |
| [`message.received`](https://pozy.ai/docs/webhooks/events#message-received) | Message received. |
| [`message.sent`](https://pozy.ai/docs/webhooks/events#message-sent) | Message sent. |
| [`message.edited`](https://pozy.ai/docs/webhooks/events#message-edited) | Message edited. |
| [`reaction.received`](https://pozy.ai/docs/webhooks/events#reaction-received) | Reaction received. |
