Skip to main content

What you can build with an MPChat bot: scenarios, patterns, and limits

See what you can ship with today's MPChat Bot API: a command-plus-MiniApp pattern, six copy-ready scenarios, and Telegram-style flows that need a workaround.

In short: An MPChat bot today is a command + MiniApp product, not a Telegram-style in-bubble button product. answerCallbackQuery, editMessageReplyMarkup, and answerInlineQuery are not exposed. Put stateful interaction in a MiniApp, then have the bot update the original chat message with editMessageText.


Overview

This page is the product-facing companion to What is an MPChat bot?. That article lists limits. This one shows what you can ship by combining the methods currently documented at core.mp.net/bots.

Do not copy a Telegram bot 1:1. The method names look familiar; the interaction model is not. Read the core pattern first, then pick a scenario.

Capability building blocks

Group today's methods by what they let the product do, not by OpenAPI category:

Block

What it is for

Primary methods

Outbound messages

Text, media, MiniApp entry, group @, link-preview control

sendMessage, sendPhoto, sendVideo, sendDocument

Message ops

Edit in place, pin, forward, copy, recall vs delete

editMessageText, pinChatMessage, unpinChatMessage, forwardMessage(s), copyMessage(s), recallMessage(s), deleteMessage(s)

Group moderation

Mute (not kick), lift mute, edit group profile

banChatMember, unbanChatMember, setChatTitle, setChatDescription, setChatPhoto

Group reads

Chat / member / admin metadata

getChat, getChatAdministrators, getChatMember, getChatMemberCount, getUserProfilePhotos

Command menu

Slash-command list the client shows

setMyCommands, getMyCommands, deleteMyCommands

MiniApp identity

Open the app, verify the user, route a screen

sendMessage + web_app.url; signed initData; ?startapp=start_param

Media methods accept a public URL or multipart upload. Existing file_id reuse is not supported. sendChatAction, sendLocation, and sendPoll currently return 501.

Core pattern: commands and MiniApps, not in-bubble buttons

Side-by-side: Telegram in-bubble buttons versus MPChat command plus MiniApp, then the chat message updates in place

Telegram's default UX is a button on the message that stays in the chat: the user taps callback_data, the bot receives callback_query, answers with answerCallbackQuery, and rewrites the keyboard with editMessageReplyMarkup.

On MPChat those three methods are listed under Common Bot API methods not currently exposed. MiniApp client return flows (web_app_data / sendData / answerWebAppQuery) are also not available. The replacement pattern is:

  1. The user sends a command, or taps a web_app button, or opens https://mp.net/{botUsername}/{shortName}?startapp=….

  2. The MiniApp loads. Your frontend reads raw window.MpChat.WebApp.initData and posts it to your backend — never put the bot token in the WebView.

  3. The backend verifies hash and auth_date, then trusts user.id, miniapp_id, and start_param.

  4. After the user finishes in the MiniApp, the backend calls Bot API editMessageText (or sends a new message) so the chat reflects the result.

Use setMyCommands for the discoverable entry points (/start, /help, /status). Use the MiniApp for anything that needs a form, a list, or more than two choices.

Scenario: group ops and pinned broadcasts

Group chat: a welcome mention for a new member, today's notice pinned, then the stale notice recalled the next day

A community bot that greets joiners and pins today's notice.

  1. Receive Update.message.new_chat_members (polling or webhook).

  2. sendMessage a welcome that @-mentions the new member with entities type text_mention (see the invite scenario below).

  3. pinChatMessage the daily notice. Group chats only; missing permission returns 403.

  4. Next day: unpinChatMessage, then recallMessage the stale notice so the timeline stays clean. recallMessage is an MPChat extension; deleteMessage remains the compatible delete.

Leave events arrive as Update.message.left_chat_member. Pins arrive as Update.message.pinned_message when the bot can see the message.

Scenario: approvals and tickets

Ticket message with an Open MiniApp button; after approve in the MiniApp the original message becomes Approved by Chen

Do not try to put Approve / Reject on the chat bubble. Open a MiniApp instead, then write the decision back into the original message.

  1. When a request is created, sendMessage a summary plus a web_app button whose url is the MiniApp entryUrl. The server resolves that URL to the current bot's MiniApp; you do not send miniapp_id.

  2. To land on one ticket, also include a direct link in the text: https://mp.net/{botUsername}/{shortName}?startapp=ticket_123. startapp becomes signed initData.start_param. Do not bake startapp into the MiniApp's saved entryUrl.

  3. The MiniApp shows Approve / Reject. After verify, your backend records the decision and calls editMessageText on the original message_id: Approved by @Chen.

If the message should stay text-only (no MiniApp card), set link_preview_options.is_disabled = true on the same sendMessage. The server still checks that web_app.url belongs to an enabled MiniApp owned by this bot.

{
  "chat_id": "12345",
  "text": "Leave request ticket_123 — open to review",
  "link_preview_options": { "is_disabled": true },
  "reply_markup": {
    "inline_keyboard": [[
      {
        "text": "Review",
        "web_app": { "url": "https://mini.example.com/demo" }
      }
    ]]
  }
}

Scenario: event invites with group mentions

Organizer picks invitees in a MiniApp; the bot then @-mentions Chen and Lei in the group

A MiniApp collects who to invite; the bot then @-mentions them in the group so they get a reminder. Official shape:

{
  "chat_id": "12345",
  "text": "@Chen @Lei invites you to this activity",
  "entities": [
    {
      "type": "text_mention",
      "offset": 0,
      "length": 5,
      "user": { "id": "2000000154" }
    },
    {
      "type": "text_mention",
      "offset": 6,
      "length": 4,
      "user": { "id": "2000000168" }
    }
  ]
}

Rules that matter in production:

  • entities currently supports only text_mention. The official reference does not state which encoding offset / length count in, and every example uses ASCII names — test with a non-ASCII display name before you ship, or the highlight will land on the wrong characters.

  • Each target must already be in the group. @all is not supported. Nicknames and fuzzy matches are not inferred.

  • If a group sendMessage omits entities entirely, the server tries to resolve raw @username text by unique group-member username and auto-fills text_mention. Ambiguous text stays plain.

  • Do not combine entities with a web_app MiniApp entry card. web_app messages also skip username auto-fill.

Scenario: a refreshable status board

One status message overwritten from 09:00 to 09:05 so the chat is not flooded

Keep one message and overwrite it instead of flooding the chat.

  1. sendMessage the first snapshot. Store chat_id + message_id.

  2. On each refresh, editMessageText that same message. Only text messages are editable; 404 if missing, 403 if the bot does not own it.

  3. For a chart, sendPhoto with a public image URL (or multipart). You cannot reuse a previous file_id, so host the image yourself and send a new URL each time.

There is no sendChatAction typing indicator (501). If generation takes a few seconds, send a short placeholder first, then editMessageText the final copy.

Scenario: content moderation

A spam message is recalled and the sender is muted; they stay in the group

An admin bot that cleans spam and mutes repeat offenders.

  • recallMessage / recallMessages (MPChat extension) or the compatible deleteMessage / deleteMessages.

  • In groups, an administrator bot with the Recall messages permission can recall regular members' messages. It cannot recall messages from the owner or other administrators — that returns 403.

  • Batch recall / delete is all-or-nothing: if any id fails the precondition, the whole request errors and nothing is partially applied.

  • banChatMember mutes the member; it does not remove them from the chat. until_date=0 or omitted means until you call unbanChatMember.

There is no createChatInviteLink / kick-and-unban cycle. To grow a group, share a MiniApp direct link with ?startapp= as your attribution tag, then have a human (or a separate product flow) add people.

Scenario: support routing and membership tiers

User opens a support MiniApp; the bot already knows the member tier and writes a closed-ticket line back to chat

A support MiniApp that already knows who opened it.

  1. Verify raw initData before you read any user field. initDataUnsafe is display-only.

  2. user.email is an MPChat extension: it appears in the signed user JSON only when the user has authorized and an Email exists; otherwise the field is omitted. Never treat a missing Email as a failed signature.

  3. user.is_premium (when present) is the hook for a paid-tier queue vs a free-tier queue.

  4. After the agent closes the ticket in the MiniApp, editMessageText or sendMessage a transcript line back into the chat so the thread stays auditable.

Telegram initData has no Email field. Do not assume a Telegram MiniApp sample will parse user.email.

What you cannot ship today — and the workaround

Telegram-style play

MP today

What to do instead

In-bubble multi-step buttons

answerCallbackQuery / editMessageReplyMarkup not exposed

web_app button or ?startapp= direct link, then editMessageText

Inline query @bot query

answerInlineQuery not exposed

setMyCommands menu + MiniApp search screen

Polls

sendPoll returns 501

MiniApp ballot; bot posts the result

Location / check-in

sendLocation returns 501

Collect location inside the MiniApp

"Typing…" indicator

sendChatAction returns 501

Placeholder text, then editMessageText

Read a file the user sent

getFile not exposed

Ask them to upload inside the MiniApp

Invite-link growth loops

createChatInviteLink family not exposed

MiniApp direct link + ?startapp= attribution

Kick a member

banChatMember only mutes

Mute via API; remove via a human admin

Payments, Stars, gifts, stickers, reactions, persistent reply keyboard

Not exposed

No Bot API substitute in this phase

Related

This page describes the method set published on core.mp.net/bots today. Confirm that page before you depend on a method that is not listed above.

Did this answer your question?