postStory
Posts a story on behalf of a managed business account. Requires the can_manage_stories business bot right. Returns Story on success.
Parameters
business_connection_idStringRequiredUnique identifier of the business connection
Content of the story
active_periodIntegerRequiredValues:
216004320086400172800Period after which the story is moved to the archive, in seconds; must be one of
6 3600, 12 3600, 86400, or 2 * 86400Caption of the story, 0-2048 characters after entities parsing
parse_modeStringOptionalMode for parsing entities in the story caption. See formatting options for more details.
A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse\_mode
A JSON-serialized list of clickable areas to be shown on the story
post_to_chat_pageBooleanOptionalPass True to keep the story accessible after it expires
protect_contentBooleanOptionalPass True if the content of the story must be protected from forwarding and screenshotting
Returns
On success, the Story object is returned.
GramIO Usage
Post a photo story from a URL on behalf of a business account:
ts
bot.on("business_message", async (ctx) => {
const story = await bot.api.postStory({
business_connection_id: ctx.businessConnectionId,
content: {
type: "photo",
photo: await MediaUpload.url("https://example.com/photo.jpg"),
},
active_period: 86400, // 24 hours
caption: "Check out our latest offer!",
});
console.log("Story posted:", story.id);
});Post a video story with a caption using rich text formatting:
ts
async function postVideoStory(businessConnectionId: string, videoPath: string) {
const story = await bot.api.postStory({
business_connection_id: businessConnectionId,
content: {
type: "video",
video: await MediaUpload.path(videoPath),
},
active_period: 21600, // 6 hours
caption: format`${bold("Flash Sale")} — 20% off everything today!`,
post_to_chat_page: true, // Keep accessible after expiry
});
return story;
}Post a photo story that is permanent and protected from forwarding:
ts
async function postProtectedStory(businessConnectionId: string) {
return bot.api.postStory({
business_connection_id: businessConnectionId,
content: {
type: "photo",
photo: await MediaUpload.url("https://example.com/banner.jpg"),
},
active_period: 172800, // 48 hours
protect_content: true,
post_to_chat_page: true,
});
}Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: business connection not found | The business_connection_id is invalid or the connection no longer exists. |
| 400 | Bad Request: not enough rights | The business bot connection does not have the can_manage_stories right. Grant this right in BotFather's business bot settings. |
| 400 | Bad Request: STORY_PERIOD_INVALID | The active_period value is not one of the four allowed values: 21600, 43200, 86400, or 172800. |
| 400 | Bad Request: story content invalid | The content object is malformed or the file could not be uploaded/processed. |
| 400 | Bad Request: caption too long | The caption exceeds 2048 characters. |
| 403 | Forbidden: not enough rights | The bot is not authorized to manage stories for this business account. |
| 429 | Too Many Requests: retry after N | Flood control triggered. Wait N seconds before retrying. |
Tips & Gotchas
active_periodhas only four allowed values. You must pass exactly21600(6 h),43200(12 h),86400(24 h), or172800(48 h). Any other integer will result in a 400 error. Use the literal numbers or named constants to avoid mistakes.can_manage_storiesright is mandatory. This business bot right must be enabled in the business connection settings; it is separate from general message rights. Check withgetBusinessConnectionfirst if you are unsure.- File uploads require
await. BothMediaUpload.url()andMediaUpload.path()are async — alwaysawaitthem before embedding in thecontentobject.MediaUpload.buffer()is synchronous if you already have the binary data. post_to_chat_pagevs.protect_content.post_to_chat_page: truemakes the story persist on the account's chat page even after theactive_periodexpires.protect_content: trueprevents viewers from forwarding or saving the media — they are independent flags and can be combined.- Do not use
parse_modetogether withcaption_entities. These are mutually exclusive. Pass one or the other:formattagged template (which returns entities) or aparse_modestring — never both. - Stories are tied to a business connection. Unlike regular bot messages, stories posted via
postStoryappear on the business account's profile, not the bot's own profile.
See Also
- editStory — Edit the caption or content of a posted story
- deleteStory — Remove a story from the business account
- repostStory — Repost a story to another managed business account
- getBusinessConnection — Inspect business connection rights before posting
- Story — The Story object returned on success
- InputStoryContent — Describes the photo or video content of a story
- StoryArea — Clickable interactive areas overlaid on the story
- formatting — Rich text formatting with the
formattag