Skip to content
Documentation menu
HTTP APITelegram

In-message ads

POST/api/v1/ad

Send your LLM response text. Sidekick selects a relevant ad, appends it to the message, and returns everything in a single response. If no ad is available, the message comes back unchanged.

Authentication

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Generate keys in your publisher settings.

Request body

FieldTypeDescription
user_idrequirednumberFinite numeric Telegram user ID (ctx.from.id). Telegram User docs →
messagerequiredstringNon-empty LLM response text to potentially inject an ad into.
platform_idrequiredstringYour platform's public ID (plt_…). platforms dashboard →
language_coderequiredstringNon-empty IETF language tag (e.g. "en", "ru"). Required even when Telegram omits language_code; use the language selected in your bot. Telegram User docs →
is_premiumbooleanWhether the user has Telegram Premium. Default false. Telegram User docs →
group_idnumberTelegram chat ID (ctx.chat.id) for group/supergroup placements. When set, the ‘1 ad per N messages’ frequency and the per-day impression cap apply per-chat instead of per-user (per-user when delivery is ephemeral — group + bot_is_admin + rich accept_formats). Omit for 1:1 (private) chats. Telegram Chat docs →
participants_countnumberNon-negative group member count; cache getChatMemberCount. Used with group_id for group-size filters and impression weighting. Telegram getChatMemberCount →
group_namestringOptional group title. Validated as a string, but currently not used by the ad routes after parsing.
first_namestringTelegram user's first name (ctx.from.first_name). Optional audience-profiling signal; the API keeps up to 128 characters. Telegram User docs →
user_messagestringThe user's message your bot is replying to. Can affect context matching, sensitive-topic checks and audience profiling. The API keeps up to 4096 characters.
parse_modestring"HTML", "MarkdownV2", or "Markdown". When set, ad CTA text is escaped and formatted as a hyperlink for the given parse mode.
platformstringSurface type. Default: "telegram".
accept_formatsstring[]Accepted formats: "text", "response", "card", "consent", "quiz". Defaults to ["text"]. Unknown values and unsupported capabilities are filtered out; an empty result falls back to ["text"]. Include "text" to allow ordinary ads alongside rich formats.
capabilitiesobject{ "rich_messages": bool, "callbacks": bool, "custom_emoji": bool } — what your bot can forward. Rich formats are only served when the matching capability is declared. See Rich formats below.
bot_is_adminbooleanWhether your bot is an admin of the group chat (cached getChatMember). Lets group scene-1 placements deliver as ephemeral (visible only to the target user).
test_richbooleanIntegration testing: serve the network's rich-format sample campaigns round-robin, bypassing targeting and frequency caps. The full pipeline (tracking, callbacks, click redirect) runs for real. Never set in production.

Required fields.

Response — ad served

200 OK
{
"message": "Python — это высокоуровневый язык программирования...\n\n<a href=\"https://t.me/heysidekick\">Реклама от Sidekick 👇</a>\n\n<a href=\"https://sidekick-ads.com/api/v1/click/imp_a8f3d2c1e9b7\">💡 Попробуй Cursor — AI-редактор для разработчиков</a>",
"has_ad": true,
"impression_id": "imp_a8f3d2c1e9b7",
"ad": {
"text": "💡 Попробуй Cursor — AI-редактор для разработчиков",
"formatted_text": "💡 Попробуй <b>Cursor</b> — <a href=\"https://sidekick-ads.com/api/v1/click/imp_a8f3d2c1e9b7\">AI-редактор</a>",
"button_text": "Попробовать Cursor →",
"button_url": "https://sidekick-ads.com/api/v1/click/imp_a8f3d2c1e9b7"
}
}

ad.formatted_text is the rich version of ad.text, already rendered into the parse_mode you sent — it can carry links and emphasis inside the copy. Use it when you render the ad yourself instead of sending our message. It is deliberately not wrapped in the click-tracking link (nested links are invalid in Telegram), so clicks on the text aren't counted — the button still is. When a campaign has no rich copy authored, this field equals ad.text.

The message field contains your original text with the ad appended. The ad object carries the button label and a click-tracking URL — use it to render an inline button in Telegram.

Response — no ad available

200 OK
{
"message": "Python — это высокоуровневый язык программирования...",
"has_ad": false,
"impression_id": null,
"ad": null
}

When no campaign matches, the message is returned unchanged. Just use the message field regardless.

Error responses

StatusMeaning
400A required field is missing, a field value is invalid, or platform_id does not identify a platform owned by this account.
401Invalid or missing API key.