sendPaidMedia
Use this method to send paid media. On success, the sent Message is returned.
Parameters
business_connection_idStringOptionalUnique identifier of the business connection on behalf of which the message will be sent
chat_idIntegerStringRequiredUnique identifier for the target chat or username of the target channel (in the format
@channelusername). If the chat is a channel, all Telegram Star proceeds from this media will be credited to the chat's balance. Otherwise, they will be credited to the bot's balance.message_thread_idIntegerOptionalUnique identifier for the target message thread (topic) of a forum; for forum supergroups and private chats of bots with forum topic mode enabled only
direct_messages_topic_idIntegerOptionalIdentifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
star_countIntegerRequiredThe number of Telegram Stars that must be paid to buy access to the media; 1-25000
A JSON-serialized array describing the media to be sent; up to 10 items
payloadStringOptionalBot-defined paid media payload, 0-128 bytes. This will not be displayed to the user, use it for your internal processes.
Media caption, 0-1024 characters after entities parsing
parse_modeStringOptionalMode for parsing entities in the media 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
show_caption_above_mediaBooleanOptionalPass True, if the caption must be shown above the message media
disable_notificationBooleanOptionalSends the message silently. Users will receive a notification with no sound.
protect_contentBooleanOptionalProtects the contents of the sent message from forwarding and saving
allow_paid_broadcastBooleanOptionalPass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
Description of the message to reply to
reply_markupInlineKeyboardMarkupReplyKeyboardMarkupReplyKeyboardRemoveForceReplyOptional⌨️ KeyboardsAdditional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user
Returns
On success, the Message object is returned.
GramIO Usage
ts
// Send a paid photo requiring 50 Stars
bot.command("premium", (ctx) =>
ctx.sendPaidMedia(
[{ type: "photo", media: "photo_file_id" }],
50,
{ caption: "Exclusive content — thanks for your Stars!" }
)
);ts
// Send a paid album of 3 photos
bot.command("gallery", (ctx) =>
ctx.sendPaidMedia(
[
{ type: "photo", media: "photo_file_id_1" },
{ type: "photo", media: "photo_file_id_2" },
{ type: "photo", media: "photo_file_id_3" },
],
100,
{ caption: "Premium photo gallery" }
)
);ts
// Track purchases with a bot-defined payload (invisible to users)
bot.command("video", (ctx) =>
ctx.sendPaidMedia(
[{ type: "video", media: "video_file_id" }],
200,
{ payload: `uid:${ctx.from?.id}:pack1` }
)
);ts
// Upload a new video and send as paid content
bot.command("exclusive", async (ctx) =>
ctx.sendPaidMedia(
[{ type: "video", media: await MediaUpload.path("./exclusive.mp4") }],
500,
{ caption: "Exclusive video" }
)
);ts
// Direct API call — send to a channel (Stars go to channel balance)
await bot.api.sendPaidMedia({
chat_id: "@mychannel",
media: [
{ type: "photo", media: "photo_file_id" },
{ type: "video", media: "video_file_id" },
],
star_count: 150,
caption: "Premium pack",
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: chat not found | chat_id is invalid or the bot has no access to that chat |
| 400 | Bad Request: STARS_AMOUNT_INVALID | star_count is 0 or exceeds 25000 — must be in range 1–25000 |
| 400 | Bad Request: MEDIA_EMPTY | media array is empty — provide at least one item |
| 400 | Bad Request: wrong file identifier/HTTP URL specified | A file_id is malformed or the URL is inaccessible |
| 400 | Bad Request: PAYLOAD_TOO_LARGE | payload string exceeds 128 bytes |
| 403 | Forbidden: bot was blocked by the user | User blocked the bot — catch and mark as inactive |
| 403 | Forbidden: bot is not a member of the channel chat | Bot not in the target channel — add as admin first |
| 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
- Stars routing depends on
chat_id. Sending to a channel credits Stars to the channel's balance; sending to a private chat or group credits the bot's balance. Design your monetization flow accordingly. InputPaidMediais different fromInputMedia. Paid media uses plain objects{ type: "photo" | "video", media: file_id }— these are not the same asInputMediaPhoto/InputMediaVideoused insendMediaGroup. Do not useMediaInput.*()helpers here.- Caption is at the group level, not per-item. Unlike
sendMediaGroup,sendPaidMediahas no per-item caption. Setcaptionin the top-level params. star_countis 1–25000. The maximum was increased to 25,000 in Bot API 9.3. Values outside this range will error.- Use
payloadfor purchase tracking. Store a user ID or product ID inpayload(0-128 bytes, never shown to users). You'll receive it back in payment-related update callbacks. - Paid media cannot be forwarded. Users who unlock paid content cannot forward it —
protect_contentis effectively always on.
See Also
- sendMediaGroup — Send a free photo/video album
- sendPhoto — Send a single free photo
- InputPaidMedia — The paid media input union type
- InputPaidMediaPhoto — Paid photo object
- InputPaidMediaVideo — Paid video object
- Files & MediaUpload — How to upload files in GramIO
- Formatting guide — Format captions with
formatand entities - auto-retry plugin — Handle rate limits automatically