# Telegram text message API

Send text posts to a Telegram channel or group through an API or MCP server: the 4,096-character limit, link previews, connecting Turboyap's bot, example requests, and errors with fixes.

**Beta:** you can connect a Telegram account and post to it through the API in early access today. It hasn't been proven with a real production post yet. The `@turboyap/sdk` and `@turboyap/mcp` packages call the same API. [Test mode](https://turboyap.com/docs/test-mode) runs the same requests against a simulated Telegram account.

## What a Telegram text message is

A Telegram text message is a post of up to 4,096 characters in a channel or group. Telegram's Bot API sends it with `sendMessage`. In Turboyap it's `type: "text"`, and the caption is the message.

Turboyap posts through its own bot, which you add as an administrator of your channel or group. Pass `link` to choose which URL gets the link preview.

## Limits

What Telegram accepts for this post type. Turboyap's planner checks every one of these before a post is scheduled (the same data as [platform rules](https://turboyap.com/docs/platform-rules)), and each value links to the Telegram documentation it comes from.

| Limit | Value | Source |
|---|---|---|
| Media | None (text only) | [Telegram Bot API: sendMessage](https://core.telegram.org/bots/api#sendmessage) |
| Text | 4,096 characters (sent as `text`) | [Telegram Bot API: sendMessage](https://core.telegram.org/bots/api#sendmessage) |
| Link card | Yes: pass `link`, sent as `link_preview_options.url` | [Telegram Bot API: sendMessage](https://core.telegram.org/bots/api#sendmessage) |
| Rate limit | About 1 message per second in a chat, and 20 per minute in a group | [Telegram bots FAQ: hitting limits](https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this) |
| Rate limit | On a flood-control error Turboyap waits the retry_after Telegram sends | [Telegram bots FAQ: hitting limits](https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this) |

Compare with other platforms in the [social media API limits tracker](https://turboyap.com/tools/social-api-limits#telegram).

## Connect a Telegram account

1. In Telegram, open your channel or group, then **Administrators**, then **Add Admin**, and choose the Turboyap bot. The connect page and `GET /v1/connect_methods` show its exact @username.
2. Give it permission to post messages (channels) or send messages (groups). It needs nothing else.
3. Connect the channel's public @username or t.me link. For a private channel, use its numeric chat ID: open it in Telegram Web (web.telegram.org/a) and copy the number after # in the address bar. It starts with -100.

Turboyap checks that the bot can post there before it saves the account. A human with a live key can connect directly with `POST /v1/accounts` and `{ "platform": "telegram", "chat": "@yourchannel" }`. Turboyap posts to channels and groups, not to private chats with a person.

An agent never handles the account's credentials: it calls the `create_connect_link` MCP tool (or `POST /v1/connect_links` with the platform) and sends the 7-day link to the person who owns the account, whose page walks them through these steps. New accounts start on autonomy level 1, so agent posts wait for approval.

## Example requests

All three do the same thing: preview the post with a dry run, then schedule it. The idempotency key makes retries safe: send the same request again with the same key and you get the original post back, not a second one.

**Early access:** `api.turboyap.com` is open to early-access users only, and `@turboyap/sdk` and `@turboyap/mcp` aren't on npm yet. These examples show the API as built.

### curl

```bash
# Preview. Remove "dry_run" to create and schedule the post.
curl https://api.turboyap.com/v1/posts \
  -H "Authorization: Bearer $TURBOYAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "text",
    "caption": "New guide: how to tell ice cream from frozen dairy dessert. https://example.com/labels",
    "link": { "url": "https://example.com/labels" },
    "targets": [{ "account_id": "acct_telegram…" }],
    "schedule_at": "2026-10-20T18:00:00-04:00",
    "idempotency_key": "telegram-text-message-2026-10-20",
    "dry_run": true
  }'
```

### TypeScript with @turboyap/sdk

```ts
import { TurboyapClient } from "@turboyap/sdk";

const ty = new TurboyapClient({ apiKey: process.env.TURBOYAP_API_KEY! });
const account = (await ty.listAccounts()).find((a) => a.platform === "telegram")!;

const post = {
  type: "text" as const,
  caption: "New guide: how to tell ice cream from frozen dairy dessert. https://example.com/labels",
  link: { "url": "https://example.com/labels" },
  targets: [{ account_id: account.id }],
  schedule_at: "2026-10-20T18:00:00-04:00",
  idempotency_key: "telegram-text-message-2026-10-20",
};

// Preview first: every problem comes back with a fix.
const preview = await ty.createPost({ ...post, dry_run: true });
if (!preview.ok) throw new Error(preview.errors.map((e) => `${e.code}: ${e.fix}`).join("\n"));

const { post: created } = await ty.createPost(post);
console.log(created.targets[0]?.status, created.targets[0]?.next_step);
```

### Claude Code (MCP)

Add the Turboyap MCP server once, with an agent key from your workspace:

```bash
claude mcp add turboyap -e TURBOYAP_API_KEY=ty_agent_… -- npx -y @turboyap/mcp
```

Then ask:

> Post our new label guide to the Telegram channel tomorrow at 9am ET, with the preview for https://example.com/labels. Dry-run first and fix anything Telegram rejects.

The agent calls `list_accounts`, `get_platform_rules`, `create_post` with `dry_run: true`, applies any fixes, calls `create_post` again to schedule, and reports each account's `next_step` from `get_post`. The same server works in Cursor; see the [MCP quickstart](https://turboyap.com/docs/mcp-quickstart).

## How publishing works

When the scheduled time arrives, Turboyap's bot sends the post with `sendMessage`. Publishing is immediate: the target moves `scheduled` → `publishing` → `published`. `platform_url` links to the message in channels and supergroups; basic groups have no message links. Telegram's Bot API has no idempotency key, so if a response is lost Turboyap marks the target `unknown_outcome` instead of posting again.

Text posts take 4,096 characters; captions on photos and albums take 1,024.

Pass `link` on a text post to choose which URL gets the link preview.

Video and documents aren't supported yet: Turboyap's media pipeline takes images only.

## Common errors and fixes

Every error has a `code`, the `field` that caused it, and a `fix` an agent can apply without asking you. A request with several problems returns all of them in `issues`; a dry run returns them without creating anything.

| Code | When | Fix |
|---|---|---|
| `too_many_items` | Media ids on a text post. Text posts take no media. | Use `type: "image"` (one image) or `"slideshow"` (several) to post media, or remove `media_ids`. |
| `invalid_request` | A text post with no text and no `link`. | Set `caption` to the text of the post. |
| `caption_too_long` | Text over 4,096 characters. | Shorten it, or pass `targets[i].caption` with a version under 4,096 characters. |
| `schedule_in_past` | `schedule_at` is more than a minute in the past. | Use `"now"` or a future time with a timezone offset. |
| `account_unavailable` | The Telegram account needs to be reconnected. | Reconnect the account, then retry. |
| `unsupported_platform` | A target is on a platform Turboyap doesn't support yet. | Remove that target. Supported platforms: tiktok, instagram, bluesky (beta), telegram (beta), discord (beta). |
| `insufficient_scope` | The key lacks a scope the request needs, such as `publish` for `schedule_at: "now"` (agent keys don't have it by default). | Schedule a future time instead of `"now"`, omit `schedule_at` to save a draft, or use a key with the missing scope. `GET /v1/keys/me` lists the key's scopes. |
| `account_not_allowed` | The key is limited to some accounts, and a target isn't one of them. | Remove that target, or use a key whose `account_ids` include the account. |
| `forbidden_scope` | An agent key tries to approve or reject a post. | A human approves agent posts. To skip review for an account, a human sets its autonomy level to 3. |
| `unknown_outcome` | Turboyap stopped partway through publishing (for example, a restart) and can't confirm whether the post went out. It doesn't publish it again. | Check the account on the platform. If the post isn't there, create it again. |

Errors from Telegram itself appear on the target's `error` with Telegram's own code. Turboyap retries rate limits and temporary failures with backoff, and marks the account for reconnection when the bot can no longer post to the chat.

## Approval and audit

- **Level 1, review everything (default):** a post an agent schedules starts as `pending_approval` and waits until a human approves it with a human key (`POST /v1/posts/:id/approve`). Agent keys can't approve.
- **Level 3, full autopilot:** agent posts schedule directly. Every action is still logged. Level 2, guardrails, is coming soon.
- **Posts created by humans** schedule directly at any level.
- **Edits re-open review:** if an agent changes the caption or time of an approved post on a level-1 account, it goes back to `pending_approval`.
- **Dry runs show the outcome:** each target's `status_on_create` tells the agent whether the post will wait for approval.
- **Audit log:** every create, approval, edit, publish and failure is recorded with whether a human or an agent did it, the key id, and the MCP client name. The kill switch (`POST /v1/workspace/pause`) stops every publish to Telegram and every other platform at once.

Read more in [the autonomy dial](https://turboyap.com/docs/autonomy-dial).

## FAQ

### How long can a Telegram message be through the Bot API?

4,096 characters for a text message. Captions on photos and albums are shorter: 1,024 characters. Turboyap checks the right limit for each post type before scheduling.

### How do I post to a Telegram channel through an API?

Add a bot as an administrator of the channel with permission to post, then call the Bot API's `sendMessage` with the channel's @username or chat ID. With Turboyap you add the Turboyap bot, connect the channel once, then schedule posts with `POST /v1/posts` or the MCP server.

### Can I choose which link gets the preview in a Telegram post?

Yes. Pass `link` with a `url`, and Turboyap sends it as `link_preview_options.url`, so Telegram previews that page even when the text has other links.

### Does it work with private channels and groups?

Yes. Connect a private channel by its numeric chat ID, which starts with -100: open the channel in Telegram Web (web.telegram.org/a) and copy the number after # in the address bar. Groups work too, as long as the bot can send messages there.

## Related

- [Telegram photo post API](https://turboyap.com/api/telegram/photo) (beta)
- [Telegram album API](https://turboyap.com/api/telegram/album) (beta)
- [Bluesky text post API](https://turboyap.com/api/bluesky/text-post) (beta)
- [Discord message API](https://turboyap.com/api/discord/message) (beta)
- [REST API reference](https://turboyap.com/docs/api)
- [Platform rules](https://turboyap.com/docs/platform-rules)
- [Social media API limits tracker](https://turboyap.com/tools/social-api-limits)
