QivunaDevelopers

Bot API reference

Every method of Bot API 1.0: 37 methods, their parameters, limits and the errors each one can answer.

POST https://bots.qivuna.com/v1/<method>
Authorization: Bot <token>
Content-Type: application/json

Methods are case-sensitive camelCase. Send parameters as a JSON object (or multipart/form-data for the three file uploads). Read methods marked GET may also be called with GET and a query string. Every answer is {"ok": true, "result": …} or {"ok": false, "error": {…}, "request_id": …} — see Errors. Object types are on Types.

Basics#

getMe#

M1GET or POST

Who the bot is, and its current state.

No parameters.

Result: BotInfo

id is the bot number as an integer (7000000001–7999999999). Bot accounts are the only ids that are never pseudonymised.

tier is new for 14 days, then standard, or verified with the blue check. Rate limits follow it.

Updates#

getUpdates#

M1GET or POST

Long-polls for updates. See Updates and long polling.

ParameterTypeRequiredNotes
offsetIntegerNoAcknowledge every update with a lower update_id (they are deleted). Pass the last update_id you handled + 1. Values ≤ 0 are ignored.
limitIntegerNo1–100, default 100.
timeoutIntegerNoSeconds to wait when nothing is queued: 0–25, default 0 (answer at once).
allowed_updatesArray of StringNoUpdate types to receive. Stored on the bot and used by later calls and by webhooks. [] restores the default set (everything except chat_member).

Result: Array of Update

One getUpdates per bot at a time; a second one gets 409 conflict. While a webhook is set, 409 conflict (“call deleteWebhook first”).

When the platform has no free long-poll slot, the answer is [] at once with the header Retry-After: 2.

Updates are kept 24 hours, at most 10,000 per bot (the oldest are dropped beyond that).

Returned updates are deleted only when a later call acknowledges them with offset.

Errors: 400 bad_request, 409 conflict.

Messages#

sendMessage#

M1POSTwriteencrypted bots

Sends a text message to a person who started the bot, a group or a channel. Encrypted bots send envelopes instead.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
textStringOne of1–4096 characters. Exactly one of text and envelope.
entitiesArray of MessageEntityNoAt most 100. Offsets and lengths in UTF-16 code units. Not together with parse_mode.
parse_modeStringNoOnly "HTML". See Text and formatting.
reply_to_message_idIntegerNoA message of the same chat.
disable_notificationBooleanNoDeliver without a push.
protect_contentBooleanNoApps disable forwarding, saving and copying of this message.
reply_markupInlineKeyboardMarkupNoAn inline keyboard (object or JSON string). See Keyboards.
envelopeStringOne ofEncrypted bots only: an s2 envelope, at most 20,000 characters. Nothing that is plaintext (text, entities, parse_mode, reply_markup) may travel next to it.
reply_tokenStringNoWith envelope, in an encrypted group: the token from the encrypted_message update. Refused in private chats.

Result: Message. A reply in an encrypted group returns {inbox_id, date, chat}: it goes to the person's inbox, not into the group.

Groups need can_send, channels can_post. A group switched to “only admins can send” refuses bots with 403 forbidden_right (can_send).

Private chats: only people who pressed Start and did not stop the bot. Messages the person did not ask for in the last 24 hours count against the daily unsolicited cap.

Counts against: messages per second per bot, 1 a second per chat (burst 3), the per-room minute limit, and the platform ceiling. See Rate limits.

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 403 user_not_started, 403 user_blocked_bot, 403 unsolicited_limit, 403 forbidden_right, 403 e2ee_required, 403 e2ee_unsupported, 403 reply_window_closed, 409 key_not_active, 410 room_closed, 422 invalid_entities, 422 invalid_markup, 422 content_blocked, 429 rate_limited.

editMessageText#

M1POSTwriteencrypted bots

Replaces the text of one of the bot's own messages.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
message_idIntegerYesA message id as the bot received it.
textStringOne of1–4096 characters.
entitiesArray of MessageEntityNoOr parse_mode.
parse_modeStringNo"HTML".
reply_markupInlineKeyboardMarkupNoOmitting it removes the keyboard (as in Telegram). Send the keyboard again to keep it.
envelopeStringOne ofEncrypted bots, private chats only: replaces an own end-to-end encrypted message.

Result: Message

Own messages only, at most 48 hours old (422 message_too_old). Own posts in channels are always editable; can_edit_posts is not needed for them.

In an encrypted bot's private chat, text edits are refused with 403 e2ee_required; edit with envelope.

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 422 message_too_old, 403 user_blocked_bot, 403 e2ee_required, 403 e2ee_unsupported, 409 key_not_active, 410 room_closed, 422 invalid_entities, 422 invalid_markup, 422 content_blocked.

editMessageReplyMarkup#

M2POSTwrite

Replaces (or removes) the inline keyboard of one of the bot's own messages, at any age.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
message_idIntegerYesA message id as the bot received it.
reply_markupInlineKeyboardMarkupNoThe new keyboard. Omitted or {"inline_keyboard": []}: the keyboard is removed.

Result: Message

Every keyboard write gives the message a new keyboard revision: presses on an older copy of the keyboard are refused in the app, so a stale button can never reach the bot.

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 403 user_blocked_bot, 403 e2ee_required, 403 e2ee_unsupported, 410 room_closed, 422 invalid_markup, 422 content_blocked.

deleteMessage#

M1POSTwrite

Deletes one of the bot's own messages (any age), or someone else's message in a group.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
message_idIntegerYesA message id as the bot received it.

Result: true

Others' messages: groups only, the grant needs can_delete_messages, at most 48 hours old, never a message of the owner, an admin or a bot (403 target_protected). It is the app's “delete for everyone”: attachments are removed too.

Every delete of others' messages is written to the bot's audit log; the room sees at most one “deleted a message” line per bot per 10 minutes.

Encrypted bots may delete their own end-to-end encrypted messages in private chats.

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 403 forbidden_right, 403 target_protected, 422 message_too_old, 403 e2ee_unsupported, 410 room_closed, 429 rate_limited.

Chats#

getChat#

M1GET or POST

Information about a chat the bot can see.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.

Result: Chat, plus description (if set) and member_count for groups and channels.

Works for a grant suspended when the group became encrypted, and for an encrypted group the bot is attached to (is_e2ee: true).

A private chat is visible only after the person started the bot.

Errors: 400 bad_request, 404 chat_not_found.

leaveChat#

M1POSTwrite

Leaves a group or channel.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.

Result: true

The grant ends, the room gets an event line, the bot gets my_chat_member. In an encrypted group this detaches the bot.

A private chat cannot be left (400 chat_id); the person stops the bot.

Errors: 400 bad_request, 404 chat_not_found.

getChatMember#

M3GET or POST

One member's status in a group (channels: only the owner and admins).

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
user_idIntegerYesA person's id as the bot received it.

Result: ChatMember

Someone who is not in the group is shown as {id, is_bot: false, first_name: "Qivuna user"} with status left. In channels, anyone but the owner and admins is 404 user_not_found: the subscriber list is never shown to bots.

Allowed while the bot is restricted (a read).

Errors: 400 bad_request, 404 chat_not_found, 404 user_not_found, 403 e2ee_unsupported.

getChatAdministrators#

M3GET or POST

The owner and admins of a group or channel (people only, at most 100).

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.

Result: Array of ChatMember

Admins who left, and accounts that are not active, are left out.

Errors: 400 bad_request, 404 chat_not_found, 403 e2ee_unsupported.

getChatMemberCount#

M3GET or POST

How many members a group (or subscribers a channel) has.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.

Result: Integer

Errors: 400 bad_request, 404 chat_not_found, 403 e2ee_unsupported.

Keyboards#

answerCallbackQuery#

M2POSTwriteencrypted bots

Answers a button press: a short toast or an alert in the presser's app.

ParameterTypeRequiredNotes
callback_query_idStringYesFrom the callback_query (or encrypted_message) update.
textStringNoAt most 200 characters. Empty: the spinner just stops.
show_alertBooleanNoAn alert instead of a toast.
envelopeStringNoEncrypted presses: the answer sealed to the presser. text and show_alert then go inside it.

Result: true

Once per press, within 15 minutes. The app gives up waiting after 15 seconds, so answer fast; a late answer is dropped quietly.

Errors: 400 bad_request, 404 callback_not_found, 403 e2ee_required, 409 key_not_active.

Commands and profile#

setMyCommands#

M2POSTwrite

Sets the command list of one scope and language. See Commands and scopes.

ParameterTypeRequiredNotes
commandsArray of BotCommandYesAt most 100, no duplicates. [] deletes the list of that scope and language.
scopeBotCommandScopeNoDefault: {"type": "default"}.
language_codeStringNoEmpty, or a two-letter ISO 639-1 code (he, en, …).

Result: true

setMyCommands and deleteMyCommands together: 10 changes a minute per bot.

Errors: 400 bad_request, 404 chat_not_found, 429 rate_limited.

getMyCommands#

M2GET or POST

The command list of exactly one scope and language (no fallback).

ParameterTypeRequiredNotes
scopeBotCommandScopeNoAs a JSON string when called with GET.
language_codeStringNo

Result: Array of BotCommand

Errors: 400 bad_request, 404 chat_not_found.

deleteMyCommands#

M2POSTwrite

Deletes the command list of one scope and language.

ParameterTypeRequiredNotes
scopeBotCommandScopeNo
language_codeStringNo

Result: true

Errors: 400 bad_request, 404 chat_not_found, 429 rate_limited.

setMyDescription#

M1POSTwrite

The description on the bot's profile (shown before Start).

ParameterTypeRequiredNotes
descriptionStringNoAt most 512 characters. Empty clears it.
language_codeStringNoAccepted and ignored in v1: one description is stored for every language.

Result: true

Publishing a bot (QivBot → Publish) needs a description and at least one command.

Errors: 400 bad_request, 422 content_blocked, 422 content_not_allowed.

getMyDescription#

M1GET or POST

The description.

No parameters.

Result: {"description": String}

setMyShortDescription#

M1POSTwrite

The short description (search results, profile).

ParameterTypeRequiredNotes
short_descriptionStringNoAt most 120 characters. Empty clears it.

Result: true

Errors: 400 bad_request, 422 content_blocked, 422 content_not_allowed.

getMyShortDescription#

M1GET or POST

The short description.

No parameters.

Result: {"short_description": String}

Moderation#

banChatMember#

M3POSTwrite

Bans a member from a group (the app's own ban).

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
user_idIntegerYesThe member.
reasonStringNoAt most 200 characters. Kept in the bot's audit log; shown in the room's line only where the bot could post text itself.

Result: true

Groups only; needs can_ban_members. Never the creator, owners, admins or other bots.

Banning someone already banned answers true and writes nothing.

Errors: 400 bad_request, 404 chat_not_found, 404 user_not_found, 403 forbidden_right, 403 target_protected, 403 e2ee_unsupported, 410 room_closed, 422 content_blocked, 429 rate_limited.

unbanChatMember#

M3POSTwrite

Lifts a ban. Unlike Telegram, the person becomes a member again.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
user_idIntegerYesThe member.
reasonStringNoAt most 200 characters.

Result: true

Needs can_ban_members. chat_member reports kicked → member.

Errors: 400 bad_request, 404 chat_not_found, 404 user_not_found, 403 forbidden_right, 403 target_protected, 403 e2ee_unsupported, 410 room_closed, 422 content_blocked, 429 rate_limited.

restrictChatMember#

M3POSTwrite

Mutes a member of a group, for good or until a time; or lifts the mute.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
user_idIntegerYesThe member.
until_dateIntegerNoUnix time. Absent, 0, less than 30 s ahead or more than 366 days ahead: for good.
permissionsObjectNoOnly {"can_send_messages": false} (mute) or {"can_send_messages": true} (lift). Any other key → 400.
reasonStringNoAt most 200 characters.

Result: true

Groups only; needs can_restrict_members. Qivuna has one switch: muted or not.

A timed mute is lifted by the platform when it ends, unless an admin changed that member since (then the admin has the last word).

Errors: 400 bad_request, 404 chat_not_found, 404 user_not_found, 403 forbidden_right, 403 target_protected, 403 e2ee_unsupported, 410 room_closed, 422 content_blocked, 429 rate_limited.

pinChatMessage#

M3POSTwrite

Pins a message in a group.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
message_idIntegerYesA message id as the bot received it.

Result: true

Groups only; needs can_pin. A group holds up to 3 pinned messages (400 message_id beyond that).

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 403 forbidden_right, 403 e2ee_unsupported, 410 room_closed, 429 rate_limited.

unpinChatMessage#

M3POSTwrite

Unpins a message in a group.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
message_idIntegerYesRequired (there is no “unpin the latest”).

Result: true

Needs can_pin.

Errors: 400 bad_request, 404 chat_not_found, 404 message_not_found, 403 forbidden_right, 403 e2ee_unsupported, 410 room_closed, 429 rate_limited.

M3POSTwrite

Creates a new invite link of the bot's own for a group or channel.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
expire_dateIntegerNoUnix time, in the future and at most 366 days ahead.
member_limitIntegerNo1–99,999 joins.

Result: ChatInviteLink

Needs can_invite. At most 100 live links per bot per room. The room's own master link is never shown to bots, and no method ever adds a person: people join through the app.

Links stop working when revoked, expired or used up, when the bot loses can_invite or leaves, while it is restricted, and on transfer or deletion.

Errors: 400 bad_request, 404 chat_not_found, 403 forbidden_right, 403 e2ee_unsupported, 410 room_closed, 429 rate_limited.

M3POSTwrite

Revokes one of the bot's invite links.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
invite_linkStringYesA link this bot created in this chat.

Result: ChatInviteLink

Errors: 400 bad_request, 404 chat_not_found, 403 e2ee_unsupported, 429 rate_limited.

setMyDefaultAdministratorRights#

M3POSTwrite

The rights the “add bot” screen suggests. A suggestion only: admins decide.

ParameterTypeRequiredNotes
rightsChatRightsYesBooleans; only rights that can be granted in that kind of room.
for_channelsBooleanNoChannels instead of groups.

Result: true

Errors: 400 bad_request.

getMyDefaultAdministratorRights#

M3POST

The suggested rights, or the platform defaults.

ParameterTypeRequiredNotes
for_channelsBooleanNoChannels instead of groups.

Result: ChatRights

Defaults: groups can_send, can_send_media; channels can_post, can_send_media.

Media#

sendPhoto#

M3POSTwrite

Sends a picture (JPEG, PNG, WebP; HEIC is converted to JPEG).

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
photoFile upload or StringYesmultipart/form-data file (≤ 20 MB), or a file_id this bot received or sent.
captionStringNoAt most 1,024 characters.
caption_entitiesArray of MessageEntityNoAlso accepted as entities. Or parse_mode.
parse_modeStringNo"HTML".
reply_to_message_idIntegerNo
disable_notificationBooleanNo
protect_contentBooleanNo
reply_markupInlineKeyboardMarkupNo

Result: Message

See Media and getFile for types, sizes, rights and daily upload limits.

Errors: 400 bad_request, 413 payload_too_large, 404 chat_not_found, 403 user_not_started, 403 user_blocked_bot, 403 unsolicited_limit, 403 forbidden_right, 403 e2ee_required, 403 e2ee_unsupported, 410 room_closed, 422 invalid_entities, 422 invalid_markup, 422 content_blocked, 429 rate_limited.

sendDocument#

M3POSTwrite

Sends a file of a type the app accepts in chats.

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
documentFile upload or StringYesFile (≤ 20 MB) or a file_id.
captionStringNoAt most 1,024 characters.
caption_entitiesArray of MessageEntityNo
parse_modeStringNo
reply_to_message_idIntegerNo
disable_notificationBooleanNo
protect_contentBooleanNo
reply_markupInlineKeyboardMarkupNo

Result: Message

Errors: 400 bad_request, 413 payload_too_large, 404 chat_not_found, 403 user_not_started, 403 user_blocked_bot, 403 unsolicited_limit, 403 forbidden_right, 403 e2ee_required, 403 e2ee_unsupported, 410 room_closed, 422 invalid_entities, 422 invalid_markup, 422 content_blocked, 429 rate_limited.

sendVideo#

M3POSTwrite

Sends a video (MP4, MOV, WebM, 3GP).

ParameterTypeRequiredNotes
chat_idIntegerYesThe chat: a person's id (private chat), or a group's or channel's negative id, as the bot received it.
videoFile upload or StringYesFile (≤ 20 MB) or a file_id.
captionStringNoAt most 1,024 characters.
caption_entitiesArray of MessageEntityNo
parse_modeStringNo
reply_to_message_idIntegerNo
disable_notificationBooleanNo
protect_contentBooleanNo
reply_markupInlineKeyboardMarkupNo

Result: Message

Errors: 400 bad_request, 413 payload_too_large, 404 chat_not_found, 403 user_not_started, 403 user_blocked_bot, 403 unsolicited_limit, 403 forbidden_right, 403 e2ee_required, 403 e2ee_unsupported, 410 room_closed, 422 invalid_entities, 422 invalid_markup, 422 content_blocked, 429 rate_limited.

getFile#

M3GET or POST

A one-hour download link for a file the bot received or sent.

ParameterTypeRequiredNotes
file_idStringYesFrom a Message's photo, video, document or attachments.

Result: File with file_path. Download: GET https://bots.qivuna.com/v1/file/<file_path> with the same Authorization header.

The link works for this bot only, for 1 hour, and only while the file is still visible to the bot (message not deleted, the bot still in the room or the 1:1 chat). A file_id lives at most 30 days.

Errors: 404 file_not_found.

Webhooks#

setWebhook#

M4POSTwrite

Delivers updates to your HTTPS endpoint instead of getUpdates. See Webhooks.

ParameterTypeRequiredNotes
urlStringYeshttps://, port 443 or 8443, at most 512 characters, a public host (no IP in private or reserved ranges, no *.qivuna.com).
secret_tokenStringYes32–128 characters of A–Z a–z 0–9 _ -. Your HMAC key. Stored encrypted, never returned.
max_connectionsIntegerNo1–8, default 4: how many chats are delivered in parallel.
allowed_updatesArray of StringNoAs in getUpdates; stored only after the challenge passed.
encrypt_payloadBooleanNoSeal every delivery to the bot's active key (qbw1). Needs an active key. A setWebhook without it turns encryption off.

Result: true

Not available at launch: every call answers 400 webhooks_disabled until webhooks open. Use getUpdates.

The ownership challenge runs synchronously before anything is saved (up to 10 s).

Limits: 20 calls per bot per hour, 40 per owner per hour, and 30 failed challenges per destination host per hour across all bots.

If the bot changed hands or the token was revoked during the challenge, 401 token_revoked; restricted or suspended meanwhile, 403.

Errors: 400 webhooks_disabled, 400 bad_request, 422 webhook_unverified, 503 webhook_unavailable, 409 conflict, 409 key_not_active, 429 rate_limited.

deleteWebhook#

M4POST

Turns the webhook off; updates wait for getUpdates.

ParameterTypeRequiredNotes
drop_pending_updatesBooleanNoAlso delete every waiting update.

Result: true

Not a write: a restricted bot may call it. Because it is not a write, Idempotency-Key is ignored here (it is safe to repeat).

getWebhookInfo#

M4GET or POST

The webhook's state and its last error.

No parameters.

Result: WebhookInfo

With no webhook: url is "" and has_secret is false.

Encryption keys#

setMyEncryptionKey#

M5POSTwriteencrypted bots

Proposes a new bot key. Nothing changes for anybody until the owner confirms it on their phone. See Encrypted bots.

ParameterTypeRequiredNotes
x25519StringYesThe X25519 public key, 32 bytes, standard base64.
ed25519StringYesThe Ed25519 public key, 32 bytes, standard base64.
tIntegerYesNow, in unix milliseconds (±10 minutes).
popStringYesProof of possession: Ed25519 over "Qivuna.Bot.v1.pop|" ‖ bot_number ‖ x25519 ‖ ed25519 ‖ uint64_be(t), 64 bytes, base64.

Result: {"status": "proposed", "fingerprint": String}

404 not_found while encrypted bots are switched off on the platform.

5 proposals per bot per hour (each one messages the owner). A new proposal replaces an older waiting one. A key used by another bot, a small-order key and a reused proof are refused.

Errors: 400 bad_key, 404 not_found, 429 rate_limited.

getMyEncryptionKey#

M5GET or POSTencrypted bots

The active key and any waiting proposal, and the bot's own user id.

No parameters.

Result: EncryptionKeyInfo

bot_id is the bot account's internal user id: the bot value inside signed encrypted messages (QB1). It is not a secret.

Errors: 404 not_found.