Builders and Constructors

June 22, 2026 ยท View on GitHub

Inline Keyboard

Chainable builder for inline keyboards:

local kb = api.inline_keyboard()
    :row(api.row()
        :callback_data_button('Option A', 'opt_a')
        :callback_data_button('Option B', 'opt_b'))
    :row(api.row()
        :url_button('Visit Site', 'https://example.com'))

api.send_message(chat_id, 'Choose:', { reply_markup = kb })

Row button methods

MethodDescription
:callback_data_button(text, callback_data)Button that sends callback data
:url_button(text, url)Button that opens a URL
:switch_inline_query_button(text, query)Switch to inline query
:switch_inline_query_current_chat_button(text, query)Inline query in current chat
:pay_button(text, pay)Payment button

Standalone button constructors

api.url_button(text, url, encoded)
api.callback_data_button(text, callback_data, encoded)
api.switch_inline_query_button(text, query, encoded)
api.switch_inline_query_current_chat_button(text, query, encoded)
api.callback_game_button(text, callback_game, encoded)
api.pay_button(text, pay, encoded)
api.copy_text_button(text, copy_text)   -- button that copies copy_text to the clipboard

Pass encoded = true to get a JSON string instead of a table.

Two field objects used inside inline keyboard buttons:

api.web_app_info(url)              -- a WebAppInfo (button's web_app field)
api.login_url(url, opts)           -- a LoginUrl; opts: forward_text, bot_username, request_write_access

Regular Keyboard

local kb = api.keyboard(true, true)  -- resize_keyboard, one_time_keyboard
    :row({'Button 1', 'Button 2'})
    :row({'Button 3'})

api.send_message(chat_id, 'Choose:', { reply_markup = kb })

Reply keyboard request buttons

Button objects for a regular (reply) keyboard. Place them in a row instead of plain strings:

api.keyboard_button_request_users(text, request_id, opts)
    -- opts: user_is_bot, user_is_premium, max_quantity, request_name, request_username, request_photo
api.keyboard_button_request_chat(text, request_id, chat_is_channel, opts)
    -- opts: chat_is_forum, chat_has_username, chat_is_created, user_administrator_rights,
    --       bot_administrator_rights, bot_is_member, request_title, request_username, request_photo
api.keyboard_button_request_contact(text)
api.keyboard_button_request_location(text)
api.keyboard_button_request_poll(text, poll_type)   -- poll_type: 'quiz', 'regular', or nil
api.keyboard_button_web_app(text, url)
local kb = api.keyboard(true, true)
    :row({ api.keyboard_button_request_contact('Share contact') })
    :row({ api.keyboard_button_request_users('Pick users', 1, { max_quantity = 3 }) })

Remove Keyboard

api.send_message(chat_id, 'Keyboard removed', {
    reply_markup = api.remove_keyboard()
})

Inline Results

Chainable builder for inline query results:

local result = api.inline_result()
    :type('article')
    :id('1')
    :title('Example Article')
    :description('This is a description')
    :input_message_content(api.input_text_message_content('Article text', 'HTML'))
    :thumbnail_url('https://example.com/thumb.jpg')
    :thumbnail_width(100)
    :thumbnail_height(100)

Available chain methods

:type(), :id(), :title(), :description(), :url(), :hide_url(), :input_message_content(), :reply_markup(), :thumbnail_url(), :thumbnail_width(), :thumbnail_height(), :photo_url(), :photo_width(), :photo_height(), :caption(), :gif_url(), :gif_width(), :gif_height(), :mpeg4_url(), :mpeg4_width(), :mpeg4_height(), :video_url(), :mime_type(), :video_width(), :video_height(), :video_duration(), :audio_url(), :performer(), :audio_duration(), :voice_url(), :voice_duration(), :document_url(), :latitude(), :longitude(), :live_period(), :address(), :foursquare_id(), :phone_number(), :first_name(), :last_name(), :game_short_name()

Input Message Content

api.input_text_message_content(message_text, parse_mode, link_preview_options, encoded)
api.input_location_message_content(latitude, longitude, encoded)
api.input_venue_message_content(latitude, longitude, title, address, foursquare_id, encoded)
api.input_contact_message_content(phone_number, first_name, last_name, encoded)

Input Media

-- Standalone constructors (return media_table, file_table)
api.input_media_photo(media, caption, parse_mode)
api.input_media_video(media, thumbnail, caption, parse_mode, width, height, duration, supports_streaming)
api.input_media_animation(media, thumbnail, caption, parse_mode, width, height, duration)
api.input_media_audio(media, thumbnail, caption, parse_mode, duration, performer, title)
api.input_media_document(media, thumbnail, caption, parse_mode)

-- Bot API 10.x media types
api.input_media_sticker(media, emoji)
api.input_media_location(latitude, longitude, horizontal_accuracy)
api.input_media_venue(latitude, longitude, title, address, opts)
api.input_media_live_photo(media, photo, opts)
api.input_media_link(url)
api.input_paid_media_live_photo(media, photo)

-- Paid media (for send_paid_media)
api.input_paid_media_photo(media)
api.input_paid_media_video(media, opts)
    -- opts: thumbnail, cover, start_timestamp, width, height, duration, supports_streaming

-- Chainable builder
local media = api.input_media()
    :photo('photo_file_id', 'First photo')
    :photo('photo_file_id_2', 'Second photo')
    :video('video_file_id', 'A video', 1280, 720, 120)

Input Poll Option

api.input_poll_option(text, opts)   -- opts: text_parse_mode, text_entities, media

Input Checklist

api.input_checklist_task(id, text, opts)   -- opts: parse_mode, text_entities
api.input_checklist(title, tasks, opts)
    -- opts: parse_mode, title_entities, others_can_add_tasks, others_can_mark_tasks_as_done
local checklist = api.input_checklist('Shopping', {
    api.input_checklist_task(1, 'Milk'),
    api.input_checklist_task(2, 'Bread')
})
api.send_checklist(chat_id, checklist)

Input Story Content

api.input_story_content_photo(photo)
api.input_story_content_video(video, opts)   -- opts: duration, cover_frame_timestamp, is_animation

Input Profile Photo

api.input_profile_photo_static(photo)
api.input_profile_photo_animated(animation, opts)   -- opts: main_frame_timestamp

Rich Message Builders (Bot API 10.1)

Sending

Build an InputRichMessage (what you send) from HTML or Markdown โ€” supply exactly one:

api.input_rich_message({ html = '<b>Hi</b>', is_rtl = false, skip_entity_detection = false })
api.input_rich_message({ markdown = '*Hi*' })

api.input_rich_message_content(rich_message)  -- wrap for inline/guest/web app results
api.link(url)                                 -- a Link object

Pass the result to api.send_rich_message, api.send_rich_message_draft, or edit_message_text's rich_message opt (see Methods).

Received structure (RichText / RichBlock)

These model the parsed message.rich_message (a RichMessage of RichBlocks, whose text is RichText). A rich text's text argument may be a plain string, an array, or another rich text.

api.rich_message(blocks, is_rtl)

-- rich text
api.rich_text_bold(text)         api.rich_text_italic(text)
api.rich_text_underline(text)    api.rich_text_strikethrough(text)
api.rich_text_spoiler(text)      api.rich_text_subscript(text)
api.rich_text_superscript(text)  api.rich_text_marked(text)
api.rich_text_code(text)
api.rich_text_date_time(text, unix_time, date_time_format)
api.rich_text_text_mention(text, user)
api.rich_text_custom_emoji(custom_emoji_id, alternative_text)   -- no text field
api.rich_text_mathematical_expression(expression)               -- no text field
api.rich_text_url(text, url)
api.rich_text_email_address(text, email_address)
api.rich_text_phone_number(text, phone_number)
api.rich_text_bank_card_number(text, bank_card_number)
api.rich_text_mention(text, username)
api.rich_text_hashtag(text, hashtag)
api.rich_text_cashtag(text, cashtag)
api.rich_text_bot_command(text, bot_command)
api.rich_text_anchor(name)                                      -- no text field
api.rich_text_anchor_link(text, anchor_name)
api.rich_text_reference(text, name)
api.rich_text_reference_link(text, reference_name)

-- rich blocks
api.rich_block_paragraph(text)
api.rich_block_heading(text, size)                  -- size 1-6
api.rich_block_preformatted(text, language)
api.rich_block_footer(text)
api.rich_block_divider()
api.rich_block_mathematical_expression(expression)
api.rich_block_anchor(name)
api.rich_block_list(items)
api.rich_block_list_item(label, blocks, opts)       -- opts: has_checkbox, is_checked, value, type
api.rich_block_blockquote(blocks, credit)
api.rich_block_pullquote(text, credit)
api.rich_block_collage(blocks, caption)
api.rich_block_slideshow(blocks, caption)
api.rich_block_table(cells, opts)                   -- opts: is_bordered, is_striped, caption
api.rich_block_table_cell(text, opts)               -- opts: is_header, colspan, rowspan, align, valign
api.rich_block_details(summary, blocks, is_open)
api.rich_block_map(location, opts)                  -- opts: zoom, width, height, caption
api.rich_block_animation(animation, opts)           -- opts: has_spoiler, caption
api.rich_block_audio(audio, caption)
api.rich_block_photo(photo, opts)                   -- opts: has_spoiler, caption
api.rich_block_video(video, opts)                   -- opts: has_spoiler, caption
api.rich_block_voice_note(voice_note, caption)
api.rich_block_caption(text, credit)
api.rich_block_thinking(text)                       -- drafts only

Prices

Chainable builder for payment prices:

local prices = api.prices()
    :labeled_price('Item', 500)
    :labeled_price('Shipping', 100)

api.send_invoice(chat_id, 'Order', 'Your order', 'payload', 'USD', prices)

Shipping Options

local options = api.shipping_options()
    :shipping_option('standard', 'Standard', api.prices():labeled_price('Standard', 500))
    :shipping_option('express', 'Express', api.prices():labeled_price('Express', 1000))

Type Constructors

Chat Permissions

api.chat_permissions({
    can_send_messages = true,
    can_send_photos = true,
    can_send_videos = true,
    can_send_polls = true,
    can_change_info = false,
    can_invite_users = true,
    can_pin_messages = false,
    can_manage_topics = false
})

Chat Administrator Rights

api.chat_administrator_rights({
    can_manage_chat = true,
    can_delete_messages = true,
    can_restrict_members = true,
    can_manage_direct_messages = true
})

Bot Commands

api.bot_command('start', 'Start the bot')
api.bot_command('help', 'Show help')

-- Scopes
api.bot_command_scope_default()
api.bot_command_scope_all_private_chats()
api.bot_command_scope_all_group_chats()
api.bot_command_scope_all_chat_administrators()
api.bot_command_scope_chat(chat_id)
api.bot_command_scope_chat_administrators(chat_id)
api.bot_command_scope_chat_member(chat_id, user_id)
api.menu_button_commands()
api.menu_button_web_app(text, web_app)
api.menu_button_default()

Reaction Types

api.reaction_type_emoji('๐Ÿ‘')
api.reaction_type_custom_emoji('custom_emoji_id')
api.reaction_type_paid()

Accepted Gift Types

For set_business_account_gift_settings:

api.accepted_gift_types({
    unlimited_gifts = true,
    limited_gifts = true,
    unique_gifts = false,
    premium_subscription = false,
    gifts_from_channels = false
})

Reply Parameters

api.reply_parameters(message_id, chat_id, allow_sending_without_reply, quote, quote_parse_mode, quote_entities, quote_position)
api.link_preview_options(is_disabled, url, prefer_small_media, prefer_large_media, show_above_text)

Message Entity

api.message_entity(entity_type, offset, length, url, user, language, custom_emoji_id)

Passport Element Errors

api.passport_element_error_data_field(error_type, field_name, data_hash, message)
api.passport_element_error_front_side(error_type, file_hash, message)
api.passport_element_error_reverse_side(error_type, file_hash, message)
api.passport_element_error_selfie(error_type, file_hash, message)
api.passport_element_error_file(error_type, file_hash, message)
api.passport_element_error_files(error_type, file_hashes, message)
api.passport_element_error_translation_file(error_type, file_hash, message)
api.passport_element_error_translation_files(error_type, file_hashes, message)
api.passport_element_error_unspecified(error_type, element_hash, message)