Telegram album API
Send 2 to 10 photos as one Telegram album to a channel or group through an API or MCP server: limits, the album caption, 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 runs the same requests against a simulated Telegram account.
What a Telegram album is
A Telegram album is 2 to 10 photos sent as one post, with one caption for the album. The Bot API sends it with sendMediaGroup. In Turboyap it's type: "slideshow" sent to a Telegram account.
Turboyap fits each photo to Telegram's limits and sends the album in one call, with the caption on the first photo so it shows on the album.
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), and each value links to the Telegram documentation it comes from.
| Limit | Value | Source |
|---|---|---|
| Images per post | 2–10 | Telegram Bot API: sendMediaGroup |
| Formats | JPEG, PNG, WebP (Turboyap converts anything else to JPEG) | Telegram Bot API: sendPhoto |
| File size | 5 MB (5,000,000 bytes) per image | Telegram Bot API: sending files |
| Dimensions | Fits 2560×2560 (Turboyap resizes to fit) | Telegram Bot API: sendPhoto |
| Aspect ratio | 1:20 to 20:1 | Telegram Bot API: sendPhoto |
| Caption | 1,024 characters (sent as caption (on the album)) | Telegram Bot API: sendMediaGroup |
| Link card | No: link is ignored on Telegram albums, with a warning | Telegram Bot API: sendMessage |
| Rate limit | About 1 message per second in a chat, and 20 per minute in a group | Telegram bots FAQ: hitting limits |
| Rate limit | On a flood-control error Turboyap waits the retry_after Telegram sends | Telegram bots FAQ: hitting limits |
Compare with other platforms in the social media API limits tracker.
Connect a Telegram account
- In Telegram, open your channel or group, then Administrators, then Add Admin, and choose the Turboyap bot. The connect page and
GET /v1/connect_methodsshow its exact @username. - Give it permission to post messages (channels) or send messages (groups). It needs nothing else.
- 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: upload the media, 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
# 1. Upload each image. The body is the raw file; Content-Type is its type.
curl https://api.turboyap.com/v1/media \
-H "Authorization: Bearer $TURBOYAP_API_KEY" \
-H "Content-Type: image/png" \
-H "X-Filename: slide-1.png" \
--data-binary @slide-1.png
# → { "media": { "id": "med_…", "width": 1080, "height": 1920, … }, "deduplicated": false }
# 2. 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": "slideshow",
"media_ids": ["med_…", "med_…", "med_…"],
"caption": "Five label tricks brands hope you miss.",
"targets": [{ "account_id": "acct_telegram…" }],
"schedule_at": "2026-10-20T18:00:00-04:00",
"fit": { "overflow": "truncate", "aspect": "pad" },
"idempotency_key": "telegram-album-2026-10-20",
"dry_run": true
}' TypeScript with @turboyap/sdk
import { readFile } from "node:fs/promises";
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 media_ids: string[] = [];
for (const file of ["slide-1.png", "slide-2.png", "slide-3.png"]) {
const { media } = await ty.uploadMedia(await readFile(file), { filename: file, contentType: "image/png" });
media_ids.push(media.id);
}
const post = {
type: "slideshow" as const,
media_ids,
caption: "Five label tricks brands hope you miss.",
targets: [{ account_id: account.id }],
schedule_at: "2026-10-20T18:00:00-04:00",
fit: { overflow: "truncate" as const, aspect: "pad" as const },
idempotency_key: "telegram-album-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:
claude mcp add turboyap -e TURBOYAP_API_KEY=ty_agent_… -- npx -y @turboyap/mcp Then ask:
Upload the slides in ~/content/labels and post them as an album to our Telegram channel on Thursday at noon ET. Dry-run first and fix anything Telegram rejects.
The agent calls list_accounts, get_platform_rules, upload_media, 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.
How publishing works
When the scheduled time arrives, Turboyap's bot sends the post with sendMediaGroup, and Telegram fetches the photos from Turboyap's media URLs. 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.
2 to 10 images post as one album (sendMediaGroup), with the caption on the album.
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 | More than 10 images for Telegram. | Set fit.overflow to "truncate" to post the first 10, or pass targets[i].media_ids with your best 10 slides (keep your call-to-action slide). |
too_few_items | Fewer than 2 images. One slide posts as a single image instead, with a warning. | Add media so there are at least 2, or send it as an image post. |
aspect_ratio_out_of_range | An image is outside 1:20 to 20:1 and fit.aspect is "strict" (the default). | Set fit.aspect to "pad" to letterbox (keeps all text visible) or "crop" to center-crop. |
caption_too_long | Caption over 1,024 characters. | Shorten it, or pass targets[i].caption with a version under 1,024 characters. |
invalid_request | link on Telegram albums. It's a warning, not an error: the post goes out without the card. | Put the URL in the caption instead, or post it as a text post. |
media_format_unsupported | A media id points to a video, or the upload isn't an image Turboyap can read. | Upload PNG, JPEG or WebP images. Video posts are coming soon. |
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_approvaland 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_createtells 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.
FAQ
How many photos can a Telegram album have?
2 to 10. Send more and Turboyap returns too_many_items; set fit.overflow to "truncate" to post the first 10. One photo posts as a single photo post instead.
Where does the caption go on a Telegram album?
On the album: Turboyap attaches it to the first photo, which is how Telegram captions an album. It can be 1,024 characters.
How do I post several images to a Telegram channel through an API?
With the Bot API's sendMediaGroup, which sends 2 to 10 photos as one album. Through Turboyap, upload the images and create a slideshow post for the Telegram account; Turboyap makes the sendMediaGroup call when the post is due.
Related
- Telegram text message API (beta)
- Telegram photo post API (beta)
- TikTok slideshow API
- Instagram carousel API
- Bluesky multi-image post API (beta)
- Discord multi-image message API (beta)
- Post one slideshow to TikTok and Instagram
- REST API reference
- Platform rules
- Social media API limits tracker
This page as markdown: /api/telegram/album.md. Everything for LLMs: /llms.txt.