editStory
Edits a story previously posted by the bot 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
story_idIntegerRequiredUnique identifier of the story to edit
Content of the story
Caption 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
Returns
On success, the Story object is returned.
GramIO Usage
ts
// Replace story content with a new photo
const story = await bot.api.editStory({
business_connection_id: "conn_abc123",
story_id: 42,
content: {
type: "photo",
photo: await MediaUpload.path("./updated-photo.jpg"),
},
});
console.log(story.id); // story ID in the business accountts
// Edit only the caption with rich formatting — entities are built automatically
await bot.api.editStory({
business_connection_id: "conn_abc123",
story_id: 42,
content: {
type: "photo",
photo: "AgACAgIAAxkBAAIBzWQ...", // reuse existing file_id
},
caption: format`${bold("New caption")} — ${italic("updated today")}`,
});ts
// Replace story with a video
await bot.api.editStory({
business_connection_id: "conn_abc123",
story_id: 7,
content: {
type: "video",
video: await MediaUpload.path("./promo.mp4"),
duration: 15,
cover_frame_timestamp: 0,
},
caption: "Check out our latest promo!",
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: story not found | story_id doesn't exist for this business connection — verify the story is still active |
| 400 | Bad Request: STORY_NOT_MODIFIED | New content and caption are identical to the current story — skip the call to avoid noise |
| 400 | Bad Request: CAPTION_TOO_LONG | caption exceeds 2048 characters — stories have twice the caption limit of media messages |
| 400 | Bad Request: can't parse entities | Malformed HTML/Markdown — use GramIO's format helper to build caption_entities safely |
| 400 | Bad Request: business connection not found | Invalid or expired business_connection_id — check your BusinessConnection update handler |
| 403 | Forbidden: not enough rights | Business bot lacks the can_manage_stories right — verify the right is granted in business settings |
| 429 | Too Many Requests: retry after N | Rate limit hit — check retry_after, use auto-retry plugin |
TIP
Use GramIO's auto-retry plugin to handle 429 errors automatically.
Tips & Gotchas
- Requires
can_manage_storiesbusiness bot right. This must be explicitly granted in the business account settings — no other right implies it. - Story caption limit is 2048 characters — double the 1024-character limit for regular media message captions. Still, keep captions concise for engagement.
parse_modeandcaption_entitiesare mutually exclusive. GramIO'sformathelper always producescaption_entities, so never passparse_modealongside it.contentis required — you always replace the media. There is no way to edit just the caption without re-supplying the content. Reuse the existingfile_idif you only need to update the caption.story_idis scoped to the business account, not a global Telegram ID. You'll get this ID from theStoryobject returned bypostStoryor from story-related updates.- Editing areas replaces all of them. To remove all clickable zones, pass an empty
areasarray.
See Also
- postStory — create a new story on behalf of a business account
- deleteStory — delete a business story
- repostStory — repost another user's story
- Story — the object returned on success
- InputStoryContent — the content union type (photo or video)
- StoryArea — clickable interactive area on a story
- Formatting guide — using
format,bold,italic, and other entity helpers - Files & media upload — uploading photos and videos with
MediaUpload