Skip to content

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_idStringRequired
Unique identifier of the business connection
story_idIntegerRequired
Unique identifier of the story to edit
contentInputStoryContentRequired
Content of the story
captionStringOptional✏️ FormattableminLen 0maxLen 2048
Caption of the story, 0-2048 characters after entities parsing
parse_modeStringOptional
Mode for parsing entities in the story caption. See formatting options for more details.
caption_entitiesMessageEntity[]Optional
A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse\_mode
areasStoryArea[]Optional
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 account
ts
// 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

CodeErrorCause
400Bad Request: story not foundstory_id doesn't exist for this business connection — verify the story is still active
400Bad Request: STORY_NOT_MODIFIEDNew content and caption are identical to the current story — skip the call to avoid noise
400Bad Request: CAPTION_TOO_LONGcaption exceeds 2048 characters — stories have twice the caption limit of media messages
400Bad Request: can't parse entitiesMalformed HTML/Markdown — use GramIO's format helper to build caption_entities safely
400Bad Request: business connection not foundInvalid or expired business_connection_id — check your BusinessConnection update handler
403Forbidden: not enough rightsBusiness bot lacks the can_manage_stories right — verify the right is granted in business settings
429Too Many Requests: retry after NRate 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_stories business 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_mode and caption_entities are mutually exclusive. GramIO's format helper always produces caption_entities, so never pass parse_mode alongside it.
  • content is required — you always replace the media. There is no way to edit just the caption without re-supplying the content. Reuse the existing file_id if you only need to update the caption.
  • story_id is scoped to the business account, not a global Telegram ID. You'll get this ID from the Story object returned by postStory or from story-related updates.
  • Editing areas replaces all of them. To remove all clickable zones, pass an empty areas array.

See Also