Add Telegram API Action
Workflow
1. Determine Action Type
- Requires chat_id? ->
Action (or MediaAction for media)
- No chat context? ->
SimpleAction (e.g. getMe, getUpdates, setWebhook)
2. Check Telegram API Spec
Consult core.telegram.org/bots/api for:
- Method name (snake_case)
- Required vs optional parameters
- Return type
3. Create Options Class (if optional params)
- Place in
telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/types/options/
data class implementing Options + mixins (OptionsCommon, OptionsParseMode, MediaSpoiler, ForumProps, etc.)
- All optional params:
var prop: Type? = null
- Add
@Serializable
- Mixin interfaces: Put optional params into separate mixin interfaces in IOptions.kt when they can be reused by other Options classes. Add a new interface (e.g.
interface MyProp : Options { var myParam: Type? }) only when the param is shared; single-use params stay in the data class.
4. Create Action Class
Place in appropriate package under telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/:
media/ - photo, video, document, etc.
message/ - sendMessage, editMessage, etc.
answer/ - answerCallbackQuery, answerInlineQuery
botactions/ - getMe, setWebhook, etc.
chat/ - getChat, banChatMember, etc.
Required:
@TgAPI on class
@TgAPI.Name("methodName") on method when Kotlin name differs from API
override val method, returnType, options (if OptionsFeature)
Features (add as needed):
OptionsFeature - optional params via options { }
MarkupFeature - reply_markup
CaptionFeature - caption, caption_entities (media)
EntitiesFeature - entities (text)
BusinessActionExt - chat-based actions
InlineActionExt - inline message actions
Parameter handling:
- Simple (String, Long, Int, Boolean):
parameters["key"] = value.toJsonElement()
- Complex objects:
value.encodeWith(MyType.serializer())
- Lists:
list.encodeWith(ListSerializer(ItemType.serializer()))
- Polymorphic ID (chat/user: Long or String):
value.encodeWith(DynamicLookupSerializer)
- Enums:
value.encodeWith(EnumType.serializer())
- Required media:
handleImplicitFile(file, "paramName") in init
- Optional media in Options (thumbnail):
handleImplicitFile(options::thumbnail) in override val beforeReq
- Complex types with nested ImplicitFile (InputProfilePhoto, InputStoryContent): transform in
beforeReq, then encodeWith(Serializer)
Use encodeWith for any @Serializable class, list, or polymorphic type; use toJsonElement() only for primitives.
5. Add Top-Level Functions
@TgAPI on each
inline fun actionName(...) = ActionClass(...)
- Overloads for
ImplicitFile, InputFile, ByteArray, () -> String as in existing media actions
- Optional
sendActionName alias
6. Validate
./gradlew formatKotlin
./gradlew prepareRelease
Reference Examples
- Media with options: Photo.kt
- Simple action with options: AnswerCallbackQuery.kt
- Complex type with beforeReq: SetMyProfilePhoto.kt
- Media with optional thumbnail: Document.kt - uses
beforeReq for handleImplicitFile(options::thumbnail)
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: vendelieu-telegram-bot-add-telegram-api-action3description: Add Telegram API Action4---56# Add Telegram API Action78## Workflow910### 1. Determine Action Type1112- **Requires chat_id?** -> `Action` (or `MediaAction` for media)13- **No chat context?** -> `SimpleAction` (e.g. getMe, getUpdates, setWebhook)1415### 2. Check Telegram API Spec1617Consult [core.telegram.org/bots/api](https://core.telegram.org/bots/api) for:18- Method name (snake_case)19- Required vs optional parameters20- Return type2122### 3. Create Options Class (if optional params)2324- Place in `telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/types/options/`25- `data class` implementing `Options` + mixins (`OptionsCommon`, `OptionsParseMode`, `MediaSpoiler`, `ForumProps`, etc.)26- All optional params: `var prop: Type? = null`27- Add `@Serializable`28- **Mixin interfaces**: Put optional params into separate mixin interfaces in IOptions.kt when they can be reused by other Options classes. Add a new interface (e.g. `interface MyProp : Options { var myParam: Type? }`) only when the param is shared; single-use params stay in the data class.2930### 4. Create Action Class3132Place in appropriate package under `telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/`:33- `media/` - photo, video, document, etc.34- `message/` - sendMessage, editMessage, etc.35- `answer/` - answerCallbackQuery, answerInlineQuery36- `botactions/` - getMe, setWebhook, etc.37- `chat/` - getChat, banChatMember, etc.3839**Required:**40- `@TgAPI` on class41- `@TgAPI.Name("methodName")` on `method` when Kotlin name differs from API42- `override val method`, `returnType`, `options` (if OptionsFeature)4344**Features** (add as needed):45- `OptionsFeature` - optional params via `options { }`46- `MarkupFeature` - reply_markup47- `CaptionFeature` - caption, caption_entities (media)48- `EntitiesFeature` - entities (text)49- `BusinessActionExt` - chat-based actions50- `InlineActionExt` - inline message actions5152**Parameter handling:**53- Simple (String, Long, Int, Boolean): `parameters["key"] = value.toJsonElement()`54- Complex objects: `value.encodeWith(MyType.serializer())`55- Lists: `list.encodeWith(ListSerializer(ItemType.serializer()))`56- Polymorphic ID (chat/user: Long or String): `value.encodeWith(DynamicLookupSerializer)`57- Enums: `value.encodeWith(EnumType.serializer())`58- Required media: `handleImplicitFile(file, "paramName")` in `init`59- Optional media in Options (thumbnail): `handleImplicitFile(options::thumbnail)` in `override val beforeReq`60- Complex types with nested ImplicitFile (InputProfilePhoto, InputStoryContent): transform in `beforeReq`, then `encodeWith(Serializer)`6162Use `encodeWith` for any `@Serializable` class, list, or polymorphic type; use `toJsonElement()` only for primitives.6364### 5. Add Top-Level Functions6566- `@TgAPI` on each67- `inline fun actionName(...) = ActionClass(...)`68- Overloads for `ImplicitFile`, `InputFile`, `ByteArray`, `() -> String` as in existing media actions69- Optional `sendActionName` alias7071### 6. Validate7273```bash74./gradlew formatKotlin75./gradlew prepareRelease76```7778## Reference Examples7980- **Media with options**: [Photo.kt](telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/media/Photo.kt)81- **Simple action with options**: [AnswerCallbackQuery.kt](telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/answer/AnswerCallbackQuery.kt)82- **Complex type with beforeReq**: [SetMyProfilePhoto.kt](telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/botactions/SetMyProfilePhoto.kt)83- **Media with optional thumbnail**: [Document.kt](telegram-bot/src/commonMain/kotlin/eu/vendeli/tgbot/api/media/Document.kt) - uses `beforeReq` for `handleImplicitFile(options::thumbnail)`8485---86> Converted and distributed by [TomeVault](https://tomevault.io/claim/vendelieu) — claim your Tome and manage your conversions.87<!-- tomevault:4.0:skill_md:2026-04-11 -->