{
  "openapi": "3.1.0",
  "info": {
    "title": "SMeet Bot API",
    "version": "1.2.0",
    "summary": "HTTP API for programs that act as SMeet bots.",
    "description": "The SMeet Bot API lets a program running on the bot author's own server receive\nupdates (messages, button presses, access changes) and reply in private chats,\ngroups, topics and channels where the bot has been granted access.\n\nThis is SMeet's own API. It is not compatible with the Telegram Bot API and no\nTelegram client library is expected to work with it.\n\n## Conventions\n\n* Every method is `POST https://messenger.scrile.com/bot-api/v1/<method>` with a JSON\n  body (`uploadFile` takes `multipart/form-data`). Read-only methods also accept `GET`\n  with query parameters.\n* Authentication: `Authorization: Bearer <BOT_TOKEN>`. The token is never passed in\n  the URL. A token belongs to exactly one bot, and a bot belongs to exactly one space\n  (the public space or one organisation); the token cannot reach any other space.\n* Every response is JSON. Success: `{\"ok\": true, \"result\": ...}`. Failure:\n  `{\"ok\": false, \"error\": {\"code\": \"...\", \"message\": \"...\", \"retry_after\": 5}, \"request_id\": \"...\"}`.\n  `retry_after` (seconds) is present only when retrying makes sense.\n* All identifiers, including `update_id`, are decimal strings. Do not convert them to\n  floating point numbers: they can exceed 2^53.\n* Unknown JSON fields may appear in any object at any time. Unknown update types must be\n  ignored, not treated as errors.\n* Mutating methods take an `Idempotency-Key` header. Repeating a request with the same key\n  and the same parameters returns the original result instead of performing the action\n  twice; the same key with different parameters fails with `IDEMPOTENCY_CONFLICT`. Keys are\n  kept for 7 days.\n* Since 1.2.0 `getMe.capabilities` lists what the server promises beyond 1.1.0. Send a\n  conditional parameter (`expected_access_revision`, `expected_installation_generation`,\n  `expected_message_revision`, `initiator`) only when its capability is listed: an older\n  server would perform the action without the condition, and a 1.2.0 server with conditions\n  switched off refuses the call with `INVALID_REQUEST` naming the parameter. A conditional\n  request repeated with the same key and body returns the first result without checking the\n  chat again.\n\n## Receiving updates\n\nA bot uses exactly one delivery mode at a time, chosen by its owner in SMeet BotFather /\n\"My bots\": long polling (`getUpdates`, the default) or webhook (SMeet POSTs each update\nto the owner's HTTPS endpoint). A bot program cannot change the mode or the webhook URL\nwith its token.\n\n`update_id` is the delivery position, `event_id` is the identity of the business event.\nA network retry keeps both. A manual replay of a FAILED update gets a new `update_id`,\nkeeps the `event_id` and sets `replay_of_update_id`. Deduplicate business actions by\n`event_id`.\n",
    "contact": {
      "name": "SMeet",
      "url": "https://messenger.scrile.com/docs/bots/en/"
    }
  },
  "servers": [
    {
      "url": "https://messenger.scrile.com/bot-api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "botToken": []
    }
  ],
  "tags": [
    {
      "name": "Bot",
      "description": "The bot's own profile and commands."
    },
    {
      "name": "Updates",
      "description": "Receiving updates with long polling."
    },
    {
      "name": "Messages",
      "description": "Sending and editing messages, answering button presses."
    },
    {
      "name": "Files",
      "description": "Photos and documents."
    },
    {
      "name": "Delivery",
      "description": "Read-only delivery diagnostics."
    }
  ],
  "paths": {
    "/getMe": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Bot"
        ],
        "summary": "Check the token and return the bot's public profile.",
        "responses": {
          "200": {
            "description": "The bot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetMeResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getMePost",
        "tags": [
          "Bot"
        ],
        "summary": "Same as GET /getMe.",
        "responses": {
          "200": {
            "description": "The bot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetMeResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getUpdates": {
      "post": {
        "operationId": "getUpdates",
        "tags": [
          "Updates"
        ],
        "summary": "Receive pending updates with long polling.",
        "description": "Returns pending updates starting at the confirmed position. Passing `offset` confirms\nevery update with `update_id < offset`; confirmed updates are never returned again.\nUnconfirmed updates are returned again on the next call (after a lost response or a\nrestart), so the program must tolerate repeats.\n\nThe request waits up to `timeout` seconds and returns as soon as an update arrives, not\nat the end of the timeout. An empty result after a timeout changes nothing.\n\nOne active consumer per bot. The first call names a `consumer_id` and receives a lease\nwith an `epoch`; later calls pass the same `consumer_id` and `epoch` and extend the\nlease (TTL 60 seconds). A second concurrent call, even with the same `consumer_id`, is\nrejected with `CONSUMER_CONFLICT`. A call carrying a foreign epoch (another consumer, the\nowner's lease reset or a mode switch took the lease since) gets a new lease but confirms\nnothing: its `offset` is ignored and unconfirmed updates come again. If your own lease\nexpired and nobody took it in between, your next call gets a new lease and its `offset`\nstill confirms.\n\nOffset rules (`confirmed_offset` = position after the confirmed prefix,\n`max_issued_update_id` = highest update_id ever returned):\n* `offset = confirmed_offset` is always accepted (a no-op confirmation).\n* `confirmed_offset < offset <= max_issued_update_id + 1` confirms the prefix.\n* `offset < confirmed_offset` fails with `409 CURSOR_BEHIND`; the error carries the\n  current `confirmed_offset`. Nothing is re-sent.\n* `offset > max_issued_update_id + 1` fails with `400 OFFSET_NOT_ISSUED` unless it\n  equals the `next_offset` the server returned for the current lease.\n* Omitting `offset` continues from the position stored by the server.\n\nExample: after update 42 was returned, `offset=43` confirms it; `offset=44` is\nrejected; once 43 is confirmed, `offset=42` gets `CURSOR_BEHIND`.\n\nUpdates that were cancelled, expired or moved to FAILED before being confirmed are\nreported in `skipped`; `next_offset` then jumps over them. Always confirm with the\nreturned `next_offset` after durably storing the whole batch.\n",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetUpdatesRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A batch of updates (possibly empty).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetUpdatesResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/rejectUpdate": {
      "post": {
        "operationId": "rejectUpdate",
        "tags": [
          "Updates"
        ],
        "summary": "Move one issued, unconfirmed update to FAILED.",
        "description": "Use when the program cannot process one specific update and does not want it to block\nthe rest of the batch. The update leaves the active sequence, keeps its payload for the\noriginal retention window, and appears in the owner's FAILED list where it can be\nreplayed or skipped. Only updates already returned to the current lease and not yet\nconfirmed can be rejected.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RejectUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The update is FAILED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RejectUpdateResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sendMessage": {
      "post": {
        "operationId": "sendMessage",
        "tags": [
          "Messages"
        ],
        "summary": "Send a text message to an allowed private, group, topic or channel chat.",
        "description": "The sender is always the bot identified by the token; there is no `sender_id`\nparameter. A private chat must still be started. A group or topic needs\n`can_send_messages`; a channel needs `can_post_messages`. Takes the conditions\n`expected_access_revision`, `expected_installation_generation` (groups, topics and\nchannels) and `initiator`. A `mini_app` button needs a private chat of a bot with a Mini\nApp.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The sent message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/editMessageText": {
      "post": {
        "operationId": "editMessageText",
        "tags": [
          "Messages"
        ],
        "summary": "Edit the text and buttons of a message this bot sent.",
        "description": "Only messages sent by this bot can be edited. If `reply_markup` is omitted, the message\nhas no buttons after the edit. Takes the conditions of sendMessage and\n`expected_message_revision`. A `mini_app` button needs a private chat of a bot with a Mini\nApp, as in sendMessage.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EditMessageTextRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The edited message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/deleteMessage": {
      "post": {
        "operationId": "deleteMessage",
        "tags": [
          "Messages"
        ],
        "summary": "Delete a message.",
        "description": "In a private chat a bot can delete only its own message. In a group, topic or\nchannel the installation needs `can_delete_messages`. Takes the conditions\n`expected_access_revision`, `expected_installation_generation` (groups, topics and\nchannels), `expected_message_revision` and `initiator`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The deleted message identity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteMessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/pinChatMessage": {
      "post": {
        "operationId": "pinChatMessage",
        "tags": [
          "Messages"
        ],
        "summary": "Pin a message in a group, topic or channel.",
        "description": "The installation needs `can_pin_messages`. Takes the conditions `expected_access_revision`,\n`expected_installation_generation`, `expected_message_revision` and `initiator`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The message is pinned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PinMessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/unpinChatMessage": {
      "post": {
        "operationId": "unpinChatMessage",
        "tags": [
          "Messages"
        ],
        "summary": "Unpin a message in a group, topic or channel.",
        "description": "The installation needs `can_pin_messages`. Takes the conditions `expected_access_revision`,\n`expected_installation_generation`, `expected_message_revision` and `initiator`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The message is unpinned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PinMessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/restrictChatMember": {
      "post": {
        "operationId": "restrictChatMember",
        "tags": [
          "Messages"
        ],
        "summary": "Remove a member from a group or channel.",
        "description": "The installation needs `can_restrict_members`. The group owner and the bot itself\ncannot be removed by this method. Takes the conditions `expected_access_revision`,\n`expected_installation_generation` and `initiator`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestrictChatMemberRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The member is removed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestrictChatMemberResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getChatContext": {
      "get": {
        "operationId": "getChatContext",
        "tags": [
          "Messages"
        ],
        "summary": "Read the current state of one chat of this bot, with its revisions.",
        "description": "For a private chat: the person and the conversation's status, also when it is stopped,\nblocked or removed. For a group, topic or channel: the group's owner, the installation's\npermissions and when it was installed. With `user_id`, whether that person is the chat's\nperson, or, in a group, known to the bot there, a member and the owner. The answer is a\nsnapshot that is out of date at once: what makes an action safe is the condition of the\nchanging call, not a read before it. Available when `capabilities` lists `chat_context`;\notherwise 404 METHOD_NOT_FOUND. Limited to 5 calls a second per bot, bursts of 10.\n",
        "parameters": [
          {
            "name": "chat_id",
            "in": "query",
            "required": true,
            "description": "`chat.id` from an update: a private chat, group, topic or channel of this bot.",
            "schema": {
              "$ref": "#/components/schemas/Id"
            }
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "A person to check; the answer is in `user_check`.",
            "schema": {
              "$ref": "#/components/schemas/Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The chat as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatContextResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getChatContextPost",
        "tags": [
          "Messages"
        ],
        "summary": "Same as GET /getChatContext.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetChatContextRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The chat as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatContextResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/answerCallbackQuery": {
      "post": {
        "operationId": "answerCallbackQuery",
        "tags": [
          "Messages"
        ],
        "summary": "Confirm that a button press was handled.",
        "description": "Stops the user's pending indicator and optionally shows a short notice. A press that is\nnot answered within 15 seconds shows \"The bot did not respond\" to the user; the bot can\nstill answer later and edit its message. A callback query can be answered once, within\n1 hour; a repeated identical answer returns the same result, and a different second answer\nfails with 409 IDEMPOTENCY_CONFLICT.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnswerCallbackQueryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Answered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrueResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getMyCommands": {
      "get": {
        "operationId": "getMyCommands",
        "tags": [
          "Bot"
        ],
        "summary": "Read the command menu.",
        "parameters": [
          {
            "name": "language_code",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/LanguageCode"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The commands.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandsResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getMyCommandsPost",
        "tags": [
          "Bot"
        ],
        "summary": "Same as GET /getMyCommands.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "language_code": {
                    "$ref": "#/components/schemas/LanguageCode"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The commands.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandsResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/setMyCommands": {
      "post": {
        "operationId": "setMyCommands",
        "tags": [
          "Bot"
        ],
        "summary": "Replace the command menu shown when the user types \"/\".",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetMyCommandsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrueResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/setMyConditionsMode": {
      "post": {
        "operationId": "setMyConditionsMode",
        "tags": [
          "Bot"
        ],
        "summary": "Switch the strict conditions mode on or off.",
        "description": "In the `strict` mode a new call of a changing method without the conditions it needs fails\nwith `400 INVALID_REQUEST` naming the missing parameter: `expected_access_revision` in a\nprivate chat; `expected_access_revision` and `expected_installation_generation` in a group,\ntopic or channel, and `expected_message_revision` too for deleteMessage. A repeat by key of\na call made before the switch still returns its result. The mode is shown in\n`getMe.conditions_mode`. Available when `capabilities` lists `strict_conditions`; otherwise\n404 METHOD_NOT_FOUND.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetMyConditionsModeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrueResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getDeliveryInfo": {
      "get": {
        "operationId": "getDeliveryInfo",
        "tags": [
          "Delivery"
        ],
        "summary": "Read the delivery mode, queue sizes and the last error.",
        "description": "Never returns the webhook secret.",
        "responses": {
          "200": {
            "description": "Delivery state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveryInfoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getDeliveryInfoPost",
        "tags": [
          "Delivery"
        ],
        "summary": "Same as GET /getDeliveryInfo.",
        "responses": {
          "200": {
            "description": "Delivery state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveryInfoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getWebhookInfo": {
      "get": {
        "operationId": "getWebhookInfo",
        "tags": [
          "Delivery"
        ],
        "summary": "Read the webhook state (a subset of getDeliveryInfo).",
        "responses": {
          "200": {
            "description": "Webhook state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookInfoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getWebhookInfoPost",
        "tags": [
          "Delivery"
        ],
        "summary": "Same as GET /getWebhookInfo.",
        "responses": {
          "200": {
            "description": "Webhook state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookInfoResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/uploadFile": {
      "post": {
        "operationId": "uploadFile",
        "tags": [
          "Files"
        ],
        "summary": "Upload a photo or document for later sending.",
        "description": "The file is stored in quarantine and scanned. The returned `file_id` has status\n`scanning`; it can be sent only after `getFile` reports `ready`. Limits: photos up to\n10 MiB (JPEG, PNG, WebP, HEIC), documents up to 20 MiB, plus a daily volume quota per\nbot. The same `Idempotency-Key` never creates a second file.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/UploadFileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The stored file (usually `scanning`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sendPhoto": {
      "post": {
        "operationId": "sendPhoto",
        "tags": [
          "Files"
        ],
        "summary": "Send a ready photo file to a chat.",
        "description": "The file must have kind `photo` (a JPEG, PNG, WebP or HEIC by its content). Any other ready\nfile fails with 400 INVALID_REQUEST, `field: file_id`; send it with sendDocument instead.\nTakes the conditions of sendMessage. A `mini_app` button needs a private chat of a bot with\na Mini App, as in sendMessage.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendFileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The sent message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/sendDocument": {
      "post": {
        "operationId": "sendDocument",
        "tags": [
          "Files"
        ],
        "summary": "Send a ready document file to a chat.",
        "description": "Takes the conditions of sendMessage. A `mini_app` button needs a private chat of a bot with\na Mini App, as in sendMessage.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyRequired"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendFileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The sent message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/getFile": {
      "get": {
        "operationId": "getFile",
        "tags": [
          "Files"
        ],
        "summary": "Read a file's metadata and processing status.",
        "description": "Works for files the bot uploaded and for attachments of messages it received. The\n`download_path` is present only while the status is `ready` and access is still\nallowed. For `scanning`, the response carries `retry_after`.\n",
        "parameters": [
          {
            "name": "file_id",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/FileId"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "getFilePost",
        "tags": [
          "Files"
        ],
        "summary": "Same as GET /getFile.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "file_id"
                ],
                "properties": {
                  "file_id": {
                    "$ref": "#/components/schemas/FileId"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileResponse"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/files/{file_id}/content": {
      "get": {
        "operationId": "downloadFile",
        "tags": [
          "Files"
        ],
        "summary": "Download the bytes of a ready file.",
        "description": "Requires the bot token and current access rights on every call. There is no public or\npermanent storage URL. Access ends when the source message is deleted, the user stops\nor blocks the bot, or the user leaves the space.\n",
        "parameters": [
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/FileId"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file bytes.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "update": {
      "post": {
        "operationId": "webhookUpdate",
        "summary": "SMeet delivers one update to the owner's HTTPS endpoint.",
        "description": "Sent only when the bot's delivery mode is `webhook`. One request in flight per bot;\nnetwork timeout 10 seconds; redirects are not followed.\n\nVerify `X-SMeet-Signature` before trusting the body: `t` is a Unix timestamp and\n`v1` is the lowercase hex HMAC-SHA256 of `\"<t>.<raw request body>\"` keyed with the\nwebhook secret shown once in \"My bots\". Reject timestamps more than 5 minutes away\nfrom your clock. The API token is never sent to the webhook.\n\nStore the update durably (unique by `event_id`) and answer any 2xx quickly; run long\nbusiness logic afterwards. A 2xx confirms receipt, not business success. Lost responses\ncause repeats with the same `update_id` and `event_id`.\n\nResponse handling: 2xx confirms. 400, 413 or 422 marks this update FAILED and moves on.\n401, 403, 404, 410, a certificate that does not validate, an address webhooks may not\nreach, a redirect and any other unsupported answer pause the endpoint until the owner\nfixes it and resumes delivery in \"My bots\" (state `paused`, the cause in `last_error`);\nnothing is retried meanwhile, no update is charged and the queue is kept. 429 slows down\nand honours `Retry-After`. DNS and connection errors, and connect or TLS handshake\ntimeouts before the request is sent, keep the update pending and back off (5 seconds,\ndoubling up to 5 minutes). 5xx, 408 and failures after the request started share a\nbudget of 5 attempts or 10 minutes per update, after which it becomes FAILED; three such\nupdates in a row open a circuit breaker that probes with the current update before\ncontinuing.\n",
        "parameters": [
          {
            "name": "X-SMeet-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "t=1790416800,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            }
          },
          {
            "name": "X-SMeet-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-SMeet-Update-Id",
            "in": "header",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Id"
            }
          },
          {
            "name": "X-SMeet-Delivery-Attempt",
            "in": "header",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Update"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted. Any 2xx is treated the same way; the body is ignored."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "botToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sbt1_<key id>_<secret>",
        "description": "The bot token shown once in \"My bots\" / SMeet BotFather. Format\n`sbt1_<key id>_<secret>`; treat it as opaque. SMeet stores only a hash. A revoked\ntoken fails with `401 INVALID_TOKEN` on every node immediately.\n"
      }
    },
    "parameters": {
      "IdempotencyKeyRequired": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Unique per logical operation (a UUID is fine). Reuse the same key when retrying after a\ntimeout, 429 or 503. Bind it to the `event_id` you are answering and the action, so a\nreplayed update does not produce a second reply.\n",
        "schema": {
          "$ref": "#/components/schemas/IdempotencyKey"
        }
      },
      "IdempotencyKeyOptional": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Accepted and not needed: the method is idempotent by itself (a repeated identical call gives\nthe same result), so the key is not stored.\n",
        "schema": {
          "$ref": "#/components/schemas/IdempotencyKey"
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Any failure. See `ErrorCode` for the meaning of each code and the HTTP status it comes\nwith. The `Retry-After` header is set whenever the body carries `retry_after` (429, 503, and\n409 CONSUMER_CONFLICT and FILE_NOT_READY).\n",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          },
          "X-Request-Id": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "Id": {
        "type": "string",
        "pattern": "^[0-9]{1,20}$",
        "description": "A decimal identifier passed as a string. Not a secret, not a permission.",
        "example": "1842"
      },
      "FileId": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{16,64}$",
        "description": "An opaque file identifier valid only for this bot.",
        "example": "f_Qm9vdGZpbGVfMDAwMDAx"
      },
      "IdempotencyKey": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "pattern": "^[A-Za-z0-9._:-]+$"
      },
      "LanguageCode": {
        "type": "string",
        "pattern": "^[a-z]{2}$",
        "example": "en"
      },
      "Timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "RFC 3339, UTC.",
        "example": "2026-09-26T10:00:00Z"
      },
      "Revision": {
        "type": "string",
        "minLength": 1,
        "maxLength": 64,
        "description": "An opaque version of an access, an installation or a message. Store it as a string and\ncompare it only for equality; never compute with it.\n",
        "example": "184502"
      },
      "UpdateType": {
        "type": "string",
        "enum": [
          "message",
          "message_edited",
          "message_deleted",
          "callback_query",
          "chat_access_changed",
          "my_chat_member",
          "delivery_gap",
          "file_status_changed",
          "mini_app_submission"
        ],
        "description": "Consumers must ignore unknown values."
      },
      "FileStatus": {
        "type": "string",
        "enum": [
          "scanning",
          "ready",
          "rejected",
          "scan_failed"
        ]
      },
      "ErrorCode": {
        "type": "string",
        "description": "| Code | HTTP | Meaning |\n|---|---|---|\n| INVALID_REQUEST | 400 | Bad text, buttons or parameters |\n| IDEMPOTENCY_KEY_REQUIRED | 400 | The method needs an Idempotency-Key header |\n| OFFSET_NOT_ISSUED | 400 | offset jumps over updates that were never returned |\n| INVALID_TOKEN | 401 | Unknown or revoked token |\n| BOT_STOPPED_OR_BLOCKED | 403 | The user stopped or blocked the bot |\n| BOT_SUSPENDED | 403 | Paused by the owner or suspended by the platform |\n| SPACE_BOTS_DISABLED | 403 | The organisation turned bot runtime off |\n| GROUP_BOT_PERMISSION_DENIED | 403 | The bot was not granted this action in the group or channel |\n| INITIATOR_NOT_AUTHORIZED | 403 | The initiator does not hold the required role now; do not retry |\n| CHAT_NOT_FOUND | 404 | No such chat for this bot (foreign chats are not listed) |\n| GROUP_BOT_NOT_INSTALLED | 404 | The group installation has ended |\n| MESSAGE_NOT_FOUND | 404 | No such message for this bot |\n| UPDATE_NOT_FOUND | 404 | The update is not issued, already confirmed or not this bot's |\n| CALLBACK_QUERY_NOT_FOUND | 404 | Unknown or expired callback query |\n| BOT_NOT_FOUND | 404 | The bot was deleted while the request was on its way; its token no longer works |\n| FILE_NOT_FOUND | 404 | Unknown file, or access to it has ended |\n| METHOD_NOT_FOUND | 404 | No such method |\n| DELIVERY_MODE_CONFLICT | 409 | getUpdates while the bot is in webhook mode |\n| CONSUMER_CONFLICT | 409 | Another poll holds the lease, or the epoch is stale; `retry_after` says when to ask again |\n| CURSOR_BEHIND | 409 | offset is below the confirmed position |\n| IDEMPOTENCY_CONFLICT | 409 | The key was used with different parameters |\n| FILE_NOT_READY | 409 | The file is still being scanned |\n| ACCESS_REVISION_CONFLICT | 409 | The access to this chat changed; expected_access_revision no longer matches. Do not retry |\n| INSTALLATION_GENERATION_CONFLICT | 409 | The bot was installed again; expected_installation_generation no longer matches. Do not retry |\n| MESSAGE_REVISION_CONFLICT | 409 | The message changed after expected_message_revision. Do not retry |\n| PAYLOAD_TOO_LARGE | 413 | The upload exceeds the size limit |\n| FILE_REJECTED | 422 | The file failed the check or is not allowed; `error.reason` says why (`not_a_photo`, `type_not_allowed`, `malware_detected`, ...) |\n| RATE_LIMITED | 429 | Too many requests; wait retry_after |\n| QUOTA_EXCEEDED | 429 | Daily file quota used up; wait retry_after |\n| TEMPORARILY_UNAVAILABLE | 503 | Transient failure; retry with the same key |\n| BOTS_MAINTENANCE | 503 | Technical pause of the bot platform; retry later with the same key and offset |\n",
        "enum": [
          "INVALID_REQUEST",
          "IDEMPOTENCY_KEY_REQUIRED",
          "OFFSET_NOT_ISSUED",
          "INVALID_TOKEN",
          "BOT_STOPPED_OR_BLOCKED",
          "BOT_SUSPENDED",
          "SPACE_BOTS_DISABLED",
          "GROUP_BOT_PERMISSION_DENIED",
          "INITIATOR_NOT_AUTHORIZED",
          "CHAT_NOT_FOUND",
          "GROUP_BOT_NOT_INSTALLED",
          "MESSAGE_NOT_FOUND",
          "UPDATE_NOT_FOUND",
          "CALLBACK_QUERY_NOT_FOUND",
          "BOT_NOT_FOUND",
          "FILE_NOT_FOUND",
          "METHOD_NOT_FOUND",
          "DELIVERY_MODE_CONFLICT",
          "CONSUMER_CONFLICT",
          "CURSOR_BEHIND",
          "IDEMPOTENCY_CONFLICT",
          "FILE_NOT_READY",
          "ACCESS_REVISION_CONFLICT",
          "INSTALLATION_GENERATION_CONFLICT",
          "MESSAGE_REVISION_CONFLICT",
          "PAYLOAD_TOO_LARGE",
          "FILE_REJECTED",
          "RATE_LIMITED",
          "QUOTA_EXCEEDED",
          "TEMPORARILY_UNAVAILABLE",
          "BOTS_MAINTENANCE"
        ]
      },
      "Error": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/ErrorCode"
          },
          "message": {
            "type": "string",
            "description": "Human-readable, English, free of secrets. Do not parse it."
          },
          "retry_after": {
            "type": "integer",
            "minimum": 1,
            "description": "Seconds to wait before retrying. Present only when a retry makes sense."
          },
          "confirmed_offset": {
            "$ref": "#/components/schemas/Id",
            "description": "Present with CURSOR_BEHIND and OFFSET_NOT_ISSUED."
          },
          "max_issued_update_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Present with OFFSET_NOT_ISSUED."
          },
          "field": {
            "type": "string",
            "description": "Present with INVALID_REQUEST when one parameter is at fault, with the four conflict and\ninitiator codes (the condition that failed, such as `expected_access_revision` or\n`initiator.user_id`), and with CHAT_NOT_FOUND and GROUP_BOT_NOT_INSTALLED about the\ninitiator's chat (`initiator.chat_id`).\n"
          },
          "reason": {
            "type": "string",
            "description": "Present with FILE_REJECTED: why the file cannot be used (`not_a_photo`, `type_not_allowed`,\n`malware_detected`, `too_large`, `empty`, `scanner_unavailable`, ...). With INVALID_REQUEST\nabout `reply_markup`, `mini_app_not_configured`: a `mini_app` button in a group or from a bot\nwithout a Mini App. Consumers must accept unknown values.\n"
          },
          "limit": {
            "type": "integer",
            "description": "Present with PAYLOAD_TOO_LARGE: the largest accepted size in bytes. A 413 answered by the\nproxy in front of the API, before the request reaches SMeet, may come without it.\n"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "ok",
          "error",
          "request_id"
        ],
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "$ref": "#/components/schemas/Error"
          },
          "request_id": {
            "type": "string"
          }
        }
      },
      "User": {
        "type": "object",
        "required": [
          "id",
          "display_name",
          "is_bot"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Id"
          },
          "display_name": {
            "type": "string"
          },
          "username": {
            "type": "string",
            "description": "Public address without \"@\", when the user has one."
          },
          "is_bot": {
            "type": "boolean"
          }
        },
        "description": "Only what the chat needs. E-mail, phone, other chats, other accounts and sessions are\nnever included.\n"
      },
      "Chat": {
        "type": "object",
        "required": [
          "id",
          "type"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Id"
          },
          "type": {
            "type": "string",
            "enum": [
              "private",
              "group",
              "channel"
            ],
            "description": "Consumers must ignore unknown values."
          },
          "group_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Parent group or channel for `group` and `channel` chats."
          },
          "title": {
            "type": "string",
            "description": "Current group or channel title."
          },
          "topic_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Present when this chat id identifies a topic inside the parent group or channel."
          },
          "access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "The version of the bot's access to this chat when the object was made: the conversation's\nfor a private chat, the installation's in the parent group for a group, topic or channel.\nPass it back as `expected_access_revision`. Present in every object of a 1.2.0 server.\n"
          },
          "installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Groups and channels only: which installation of the bot this is. Installing the bot\nagain gives a new one. Pass it back as `expected_installation_generation`.\n"
          }
        }
      },
      "Space": {
        "type": "object",
        "required": [
          "id",
          "kind"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Id"
          },
          "kind": {
            "type": "string",
            "enum": [
              "public",
              "organization"
            ]
          },
          "name": {
            "type": "string"
          }
        }
      },
      "Bot": {
        "type": "object",
        "required": [
          "id",
          "username",
          "display_name",
          "is_bot",
          "space",
          "status",
          "delivery_mode"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Id",
            "description": "The bot's account id, the same value as `from.id` of the messages the bot sends."
          },
          "username": {
            "type": "string",
            "example": "support_helper_bot"
          },
          "display_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "is_bot": {
            "const": true
          },
          "space": {
            "$ref": "#/components/schemas/Space"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused_by_owner",
              "suspended_by_admin"
            ]
          },
          "delivery_mode": {
            "type": "string",
            "enum": [
              "polling",
              "webhook"
            ]
          },
          "can_send_files": {
            "type": "boolean",
            "description": "False while file support is turned off for this installation."
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What this server promises beyond 1.1.0. `chat_context`: getChatContext.\n`access_revisions`: chats carry `access_revision` and `installation_generation`, and the\nchanging methods check the expected values. `message_revisions`: messages carry\n`message_revision`, checked as `expected_message_revision`. `initiator_conditions`: the\nchanging methods check `initiator`. `strict_conditions`: setMyConditionsMode and\n`conditions_mode`. `mini_apps`: the `mini_app` button and the `mini_app_submission`\nupdate. Skip values you do not know. Missing on a server that promises none of them.\n"
          },
          "conditions_mode": {
            "type": "string",
            "enum": [
              "optional",
              "strict"
            ],
            "description": "Present with the conditions' capabilities; set with setMyConditionsMode."
          },
          "mini_app": {
            "$ref": "#/components/schemas/BotMiniApp",
            "description": "The bot's Mini App, while `capabilities` lists `mini_apps` and the bot has one."
          }
        }
      },
      "BotMiniApp": {
        "type": "object",
        "required": [
          "id",
          "status",
          "published"
        ],
        "description": "The Mini App of a bot, as getMe describes it.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Id",
            "description": "The same value as `app_id` of `mini_app_submission`."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused_by_owner",
              "blocked_by_admin"
            ],
            "description": "Consumers must ignore unknown values."
          },
          "published": {
            "type": "boolean",
            "description": "Whether a reviewed configuration is live. A `mini_app` button opens only the published\none; until then a person sees that the Mini App is not available yet.\n"
          }
        }
      },
      "MiniAppButton": {
        "type": "object",
        "description": "Opens the bot's Mini App in the person's SMeet app, the published version only.",
        "properties": {
          "start_param": {
            "type": "string",
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9_-]*$",
            "description": "Handed to the Mini App when it opens. Empty or missing: no parameter. The Mini App's own\nserver sees it after login, and a submission does not repeat it.\n"
          }
        }
      },
      "InlineKeyboardButton": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "callback_data": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "description": "Returned in callback_query.data when pressed. Exactly one of callback_data, url or mini_app."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "An https:// link opened by the client. Exactly one of callback_data, url or mini_app."
          },
          "mini_app": {
            "$ref": "#/components/schemas/MiniAppButton",
            "description": "Opens the bot's Mini App (capability `mini_apps`). Only in a private chat of a bot that has\na Mini App; otherwise INVALID_REQUEST with `reason` `mini_app_not_configured`. The bot is not\ntold about a press. Exactly one of callback_data, url or mini_app.\n"
          }
        }
      },
      "InlineKeyboardMarkup": {
        "type": "object",
        "required": [
          "inline_keyboard"
        ],
        "properties": {
          "inline_keyboard": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "description": "Rows of buttons; at most 8 buttons per row and 40 in total.",
            "items": {
              "type": "array",
              "minItems": 1,
              "maxItems": 8,
              "items": {
                "$ref": "#/components/schemas/InlineKeyboardButton"
              }
            }
          }
        }
      },
      "Attachment": {
        "type": "object",
        "required": [
          "file_id",
          "kind",
          "file_name",
          "size",
          "processing_status"
        ],
        "properties": {
          "file_id": {
            "$ref": "#/components/schemas/FileId"
          },
          "kind": {
            "type": "string",
            "enum": [
              "photo",
              "document",
              "voice"
            ],
            "description": "`voice` is a person's voice message: the recording alone, with `duration` and, when the\nsender's app recognised the speech, `transcription`.\n"
          },
          "file_name": {
            "type": "string",
            "description": "Sanitised name, safe to display and to use as a download name."
          },
          "mime_type": {
            "type": "string",
            "description": "As the sender's app declared it. The type detected from the content is in `getFile` once\nthe check is done: markup, programs and other dangerous types are refused there\n(`type_not_allowed`), and any other mismatch is stored under the detected type (a \"photo\"\nthat is not a picture becomes a document).\n"
          },
          "size": {
            "type": "integer",
            "minimum": 0,
            "description": "As the sender's app declared it; `getFile` has the size of the stored copy."
          },
          "processing_status": {
            "$ref": "#/components/schemas/FileStatus"
          },
          "reason": {
            "type": "string",
            "description": "Only when the attachment is already `rejected` or `scan_failed`, for example `too_large` for an\nattachment above the size a bot may receive. Same values as File.reason.\n"
          },
          "duration": {
            "type": "integer",
            "minimum": 0,
            "description": "Voice only. Length of the recording in whole seconds, as the sender's app measured it."
          },
          "transcription": {
            "type": "string",
            "description": "Voice only, and only when the sender's app recognised the speech. A convenience, not a\nguarantee: download the audio for anything that must be exact. The sender may replace it,\nand neither `message_revision` nor `message_edited` follows that.\n"
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "message_id",
          "chat",
          "from",
          "date"
        ],
        "properties": {
          "message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "chat": {
            "$ref": "#/components/schemas/Chat"
          },
          "from": {
            "$ref": "#/components/schemas/User"
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "edit_date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "text": {
            "type": "string",
            "maxLength": 4096
          },
          "reply_to_message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Attachment"
            }
          },
          "reply_markup": {
            "$ref": "#/components/schemas/InlineKeyboardMarkup"
          },
          "has_unsupported_content": {
            "type": "boolean",
            "description": "True when the message carries content this API version does not expose (round video,\nlocation, poll and the like). `text` then holds the readable fallback, if any. A voice\nmessage is not among them: it arrives as a `voice` attachment.\n"
          },
          "message_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "The version of this message: it changes with every edit of its text or quote, not with a\nvoice message's transcription. Present in `message`, `edited_message` and the results of\nsending and editing; pass it back as `expected_message_revision`.\n"
          }
        }
      },
      "CallbackQuery": {
        "type": "object",
        "required": [
          "id",
          "from",
          "message",
          "data",
          "date"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Pass to answerCallbackQuery."
          },
          "from": {
            "$ref": "#/components/schemas/User"
          },
          "message": {
            "type": "object",
            "required": [
              "message_id",
              "chat"
            ],
            "description": "The bot's message whose button was pressed.",
            "properties": {
              "message_id": {
                "$ref": "#/components/schemas/Id"
              },
              "chat": {
                "$ref": "#/components/schemas/Chat"
              }
            }
          },
          "data": {
            "type": "string"
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "ChatAccess": {
        "type": "object",
        "required": [
          "chat",
          "user",
          "status",
          "date"
        ],
        "properties": {
          "chat": {
            "$ref": "#/components/schemas/Chat",
            "description": "With the `access_revision` after the change."
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "status": {
            "type": "string",
            "enum": [
              "started",
              "stopped",
              "blocked",
              "removed"
            ],
            "description": "`started`: the user pressed Start (again). `stopped`: the user pressed Stop.\n`blocked`: the user blocked the bot, or added the bot's account to their general block\nlist; taking it off that list sends no update. `removed`: the user left the bot's space,\nso the platform withdrew the bot's access. After anything but `started`, sending to this\nchat fails with BOT_STOPPED_OR_BLOCKED.\n"
          },
          "start_param": {
            "type": "string",
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9_-]*$",
            "description": "The deep-link parameter of a `?start=` link, for `started` only. Never a command itself, but\nStart also puts a visible message from the user in the chat, `/start` or `/start <param>`,\nwhich arrives as its own `message` update right after this one. A bot that greets on Start\nshould react to one of the two, not both.\n"
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "GroupBotPermissions": {
        "type": "object",
        "required": [
          "read_all_messages",
          "can_send_messages",
          "can_edit_messages",
          "can_delete_messages",
          "can_pin_messages",
          "can_restrict_members",
          "can_post_messages"
        ],
        "properties": {
          "read_all_messages": {
            "type": "boolean",
            "description": "Receive every new human message. Without it, only addressed messages are delivered."
          },
          "can_send_messages": {
            "type": "boolean",
            "description": "Send to groups and their topics."
          },
          "can_edit_messages": {
            "type": "boolean"
          },
          "can_delete_messages": {
            "type": "boolean"
          },
          "can_pin_messages": {
            "type": "boolean"
          },
          "can_restrict_members": {
            "type": "boolean"
          },
          "can_post_messages": {
            "type": "boolean",
            "description": "Publish in channels; independent from `can_send_messages`."
          }
        }
      },
      "MyChatMember": {
        "type": "object",
        "required": [
          "chat",
          "from",
          "status",
          "permissions",
          "date"
        ],
        "properties": {
          "chat": {
            "$ref": "#/components/schemas/Chat",
            "description": "With the `access_revision` and `installation_generation` after the change."
          },
          "from": {
            "$ref": "#/components/schemas/User",
            "description": "The person who installed, updated or removed the bot."
          },
          "status": {
            "type": "string",
            "enum": [
              "member",
              "left"
            ]
          },
          "permissions": {
            "$ref": "#/components/schemas/GroupBotPermissions"
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "DeliveryGap": {
        "type": "object",
        "required": [
          "chat",
          "dropped_count",
          "first_dropped_at",
          "last_dropped_at"
        ],
        "description": "A summary emitted after group-message backpressure ends. It says that new messages\nwere deliberately not queued; it never contains the dropped message bodies.\n",
        "properties": {
          "chat": {
            "$ref": "#/components/schemas/Chat"
          },
          "dropped_count": {
            "type": "integer",
            "minimum": 1
          },
          "first_dropped_at": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "last_dropped_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "DeletedMessage": {
        "type": "object",
        "required": [
          "message_id",
          "chat",
          "date"
        ],
        "properties": {
          "message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "chat": {
            "$ref": "#/components/schemas/Chat"
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "FileStatusChange": {
        "type": "object",
        "required": [
          "file_id",
          "status"
        ],
        "description": "Sent when a check ends: for attachments the bot received (with `message_id` and `chat`), and for\nthe bot's own uploads (without them). Never sent into a chat the user has stopped or left.\n`scan_failed` is not always final: a file the scanner could not check (`scanner_unavailable`,\n`scanner_outdated`, `scan_timeout`) is checked again about an hour later, up to three rounds,\nand another file_status_changed follows; meanwhile getFile reports `scanning` again.\n",
        "properties": {
          "file_id": {
            "$ref": "#/components/schemas/FileId"
          },
          "status": {
            "$ref": "#/components/schemas/FileStatus"
          },
          "message_id": {
            "$ref": "#/components/schemas/Id",
            "description": "The message the file is attached to, for received attachments."
          },
          "chat": {
            "$ref": "#/components/schemas/Chat",
            "description": "The chat of that message. For an attachment received in a group or topic it is the group\nchat, with `group_id`, `title` and `topic_id`.\n"
          },
          "reason": {
            "type": "string",
            "description": "For rejected and scan_failed. Values: `malware_detected`, `type_not_allowed` (markup, programs and\nother refused types), `too_large` (a file above the limit is rejected; one the scanner refuses\nfor its size ends as scan_failed), `empty` (no content), `scanner_unavailable`, `scanner_outdated`\n(signatures older than 3 days), `scan_timeout`, `source_missing` (the attachment disappeared\nbefore the check). Consumers must accept unknown values.\n"
          }
        }
      },
      "Update": {
        "type": "object",
        "required": [
          "update_id",
          "event_id",
          "type",
          "date"
        ],
        "description": "Exactly one payload field is present, chosen by `type`:\n\n| type | payload field |\n|---|---|\n| message | message |\n| message_edited | edited_message |\n| message_deleted | deleted_message |\n| callback_query | callback_query |\n| chat_access_changed | chat_access |\n| my_chat_member | my_chat_member |\n| delivery_gap | delivery_gap |\n| file_status_changed | file_status |\n| mini_app_submission | mini_app_submission |\n\nEditing an old message is not a new command: treat `message_edited` as a correction. The\nrevisions in a payload are those of the moment the event happened, and a replay from FAILED\nhands them over unchanged; updates written before 1.2.0 have none.\n",
        "properties": {
          "update_id": {
            "$ref": "#/components/schemas/Id"
          },
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "$ref": "#/components/schemas/UpdateType"
          },
          "replay_of_update_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Set when the owner replayed a FAILED update."
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "message": {
            "$ref": "#/components/schemas/Message"
          },
          "edited_message": {
            "$ref": "#/components/schemas/Message"
          },
          "deleted_message": {
            "$ref": "#/components/schemas/DeletedMessage"
          },
          "callback_query": {
            "$ref": "#/components/schemas/CallbackQuery"
          },
          "chat_access": {
            "$ref": "#/components/schemas/ChatAccess"
          },
          "my_chat_member": {
            "$ref": "#/components/schemas/MyChatMember"
          },
          "delivery_gap": {
            "$ref": "#/components/schemas/DeliveryGap"
          },
          "file_status": {
            "$ref": "#/components/schemas/FileStatusChange"
          },
          "mini_app_submission": {
            "$ref": "#/components/schemas/MiniAppSubmission"
          }
        }
      },
      "MiniAppSubmission": {
        "type": "object",
        "required": [
          "id",
          "app_id",
          "environment",
          "client_request_id",
          "from",
          "chat",
          "data",
          "date"
        ],
        "description": "A person sent a form of the bot's Mini App to the bot and confirmed it in SMeet. SMeet fixes\nthe application, the environment, the person and the chat; the page sends only `data`. One\nsubmission is one update, whatever the page retries.\n",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The submission, as the person's app and the Mini App know it."
          },
          "app_id": {
            "$ref": "#/components/schemas/Id"
          },
          "environment": {
            "type": "string",
            "enum": [
              "production",
              "test"
            ],
            "description": "`test` comes only from the owner, accepted testers and reviewers."
          },
          "client_request_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9._:-]+$",
            "description": "The page's `requestId` of this form. A retry of the page with the same one is the same\nsubmission and gives no second update.\n"
          },
          "from": {
            "$ref": "#/components/schemas/User"
          },
          "chat": {
            "$ref": "#/components/schemas/Chat",
            "description": "The private chat of the person with the bot, with the `access_revision` the Mini App was\nopened with. Answer there, with this revision as `expected_access_revision`.\n"
          },
          "data": {
            "type": "object",
            "description": "The form as the page sent it, a JSON object of up to 16 KiB."
          },
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "Lease": {
        "type": "object",
        "required": [
          "consumer_id",
          "epoch",
          "expires_at"
        ],
        "properties": {
          "consumer_id": {
            "type": "string"
          },
          "epoch": {
            "$ref": "#/components/schemas/Id"
          },
          "expires_at": {
            "$ref": "#/components/schemas/Timestamp"
          }
        }
      },
      "SkipRange": {
        "type": "object",
        "required": [
          "from_update_id",
          "to_update_id",
          "reason"
        ],
        "properties": {
          "from_update_id": {
            "$ref": "#/components/schemas/Id"
          },
          "to_update_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Inclusive."
          },
          "reason": {
            "type": "string",
            "enum": [
              "cancelled",
              "failed",
              "expired",
              "skipped_by_owner",
              "delivered"
            ],
            "description": "`cancelled`: access to the chat or its source ended before delivery, or a Mini App's\nsubmission lost its application. `failed`: moved to FAILED\n(rejectUpdate or the webhook budget). `expired`: the retention window ran out. `skipped_by_owner`:\nthe owner skipped a FAILED update. `delivered`: already confirmed another way, for example by the\nwebhook before the owner switched the bot back to long polling. Consumers must accept unknown values.\n"
          }
        }
      },
      "GetUpdatesRequest": {
        "type": "object",
        "required": [
          "consumer_id"
        ],
        "properties": {
          "offset": {
            "$ref": "#/components/schemas/Id"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 100
          },
          "timeout": {
            "type": "integer",
            "minimum": 0,
            "maximum": 25,
            "default": 25,
            "description": "Seconds to wait when nothing is pending. 0 returns immediately."
          },
          "consumer_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9._-]+$",
            "description": "A stable name of this receiving process, e.g. its host name."
          },
          "epoch": {
            "$ref": "#/components/schemas/Id",
            "description": "The epoch of the lease received earlier. Keep it with your offset and pass it after a restart\ntoo; omit it only when you have none. Without it, a lease this consumer still holds answers\n409 CONSUMER_CONFLICT until it expires (retry_after tells how long); then call again.\n"
          }
        }
      },
      "GetUpdatesResult": {
        "type": "object",
        "required": [
          "updates",
          "confirmed_offset",
          "next_offset",
          "skipped",
          "lease"
        ],
        "properties": {
          "updates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Update"
            }
          },
          "confirmed_offset": {
            "$ref": "#/components/schemas/Id",
            "description": "Position after the confirmed prefix, after applying this request's offset."
          },
          "next_offset": {
            "$ref": "#/components/schemas/Id",
            "description": "Pass as `offset` after durably storing every update of this batch."
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkipRange"
            }
          },
          "lease": {
            "$ref": "#/components/schemas/Lease"
          },
          "queue_gap": {
            "type": "boolean",
            "description": "True when updates expired before delivery since the last confirmation."
          }
        }
      },
      "GetUpdatesResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/GetUpdatesResult"
          }
        }
      },
      "RejectUpdateRequest": {
        "type": "object",
        "required": [
          "update_id",
          "reason",
          "consumer_id",
          "epoch"
        ],
        "properties": {
          "update_id": {
            "$ref": "#/components/schemas/Id"
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256,
            "description": "Shown to the owner. Must not contain secrets or personal data."
          },
          "consumer_id": {
            "type": "string"
          },
          "epoch": {
            "$ref": "#/components/schemas/Id"
          }
        }
      },
      "RejectUpdateResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "type": "object",
            "required": [
              "update_id",
              "status"
            ],
            "properties": {
              "update_id": {
                "$ref": "#/components/schemas/Id"
              },
              "status": {
                "const": "failed"
              }
            }
          }
        }
      },
      "SendMessageRequest": {
        "type": "object",
        "required": [
          "chat_id",
          "text"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096,
            "description": "Plain text. Strings starting with \"__META__:\" or \"__SYSTEM__\" are rejected."
          },
          "reply_to_message_id": {
            "$ref": "#/components/schemas/Id",
            "description": "A message in the same chat."
          },
          "reply_markup": {
            "$ref": "#/components/schemas/InlineKeyboardMarkup"
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the chat's `access_revision` is this one; otherwise 409 ACCESS_REVISION_CONFLICT."
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Groups, topics and channels: act only while the installation is this one; otherwise 409\nINSTALLATION_GENERATION_CONFLICT. In a private chat, 400 INVALID_REQUEST.\n"
          },
          "initiator": {
            "$ref": "#/components/schemas/Initiator"
          }
        }
      },
      "EditMessageTextRequest": {
        "type": "object",
        "required": [
          "chat_id",
          "message_id",
          "text"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096
          },
          "reply_markup": {
            "$ref": "#/components/schemas/InlineKeyboardMarkup"
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the chat's `access_revision` is this one; otherwise 409 ACCESS_REVISION_CONFLICT."
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Groups, topics and channels: act only while the installation is this one; otherwise 409\nINSTALLATION_GENERATION_CONFLICT. In a private chat, 400 INVALID_REQUEST.\n"
          },
          "expected_message_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the message's `message_revision` is this one; otherwise 409 MESSAGE_REVISION_CONFLICT."
          },
          "initiator": {
            "$ref": "#/components/schemas/Initiator"
          }
        }
      },
      "ChatMessageRequest": {
        "type": "object",
        "required": [
          "chat_id",
          "message_id"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the chat's `access_revision` is this one; otherwise 409 ACCESS_REVISION_CONFLICT."
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Groups, topics and channels: act only while the installation is this one; otherwise 409\nINSTALLATION_GENERATION_CONFLICT. In a private chat, 400 INVALID_REQUEST.\n"
          },
          "expected_message_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the message's `message_revision` is this one; otherwise 409 MESSAGE_REVISION_CONFLICT."
          },
          "initiator": {
            "$ref": "#/components/schemas/Initiator"
          }
        }
      },
      "RestrictChatMemberRequest": {
        "type": "object",
        "required": [
          "chat_id",
          "user_id"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "user_id": {
            "$ref": "#/components/schemas/Id"
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the installation's `access_revision` is this one; otherwise 409 ACCESS_REVISION_CONFLICT."
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the installation is this one; otherwise 409 INSTALLATION_GENERATION_CONFLICT."
          },
          "initiator": {
            "$ref": "#/components/schemas/Initiator"
          }
        }
      },
      "AnswerCallbackQueryRequest": {
        "type": "object",
        "required": [
          "callback_query_id"
        ],
        "properties": {
          "callback_query_id": {
            "type": "string"
          },
          "text": {
            "type": "string",
            "maxLength": 200,
            "description": "A short notice shown to the user."
          },
          "show_alert": {
            "type": "boolean",
            "default": false,
            "description": "Show the notice as a dialog instead of a toast."
          }
        }
      },
      "MessageResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/Message"
          }
        }
      },
      "DeleteMessageResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "type": "object",
            "required": [
              "message_id",
              "chat",
              "deleted"
            ],
            "properties": {
              "message_id": {
                "$ref": "#/components/schemas/Id"
              },
              "chat": {
                "$ref": "#/components/schemas/Chat"
              },
              "deleted": {
                "const": true
              }
            }
          }
        }
      },
      "PinMessageResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "type": "object",
            "required": [
              "message_id",
              "chat",
              "pinned"
            ],
            "properties": {
              "message_id": {
                "$ref": "#/components/schemas/Id"
              },
              "chat": {
                "$ref": "#/components/schemas/Chat"
              },
              "pinned": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "RestrictChatMemberResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "type": "object",
            "required": [
              "chat",
              "user_id",
              "restricted"
            ],
            "properties": {
              "chat": {
                "$ref": "#/components/schemas/Chat"
              },
              "user_id": {
                "$ref": "#/components/schemas/Id"
              },
              "restricted": {
                "const": true
              }
            }
          }
        }
      },
      "TrueResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "const": true
          }
        }
      },
      "BotCommand": {
        "type": "object",
        "required": [
          "command",
          "description"
        ],
        "properties": {
          "command": {
            "type": "string",
            "pattern": "^[a-z0-9_]{1,32}$",
            "description": "Without the leading slash."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          }
        }
      },
      "SetMyCommandsRequest": {
        "type": "object",
        "required": [
          "commands"
        ],
        "properties": {
          "commands": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/BotCommand"
            }
          },
          "language_code": {
            "$ref": "#/components/schemas/LanguageCode",
            "description": "Omit for the default list shown to every language."
          }
        }
      },
      "CommandsResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BotCommand"
            }
          }
        }
      },
      "DeliveryError": {
        "type": "object",
        "required": [
          "date",
          "code"
        ],
        "properties": {
          "date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "code": {
            "type": "string",
            "description": "Before the request left: DNS_ERROR, CONNECT_ERROR, CONNECT_TIMEOUT, TLS_ERROR. After it left:\nTIMEOUT, NO_RESPONSE, IO_ERROR, HTTP_408, HTTP_5xx (the status itself, for example HTTP_503).\nPausing until the owner resumes: HTTP_401, HTTP_403, HTTP_404, HTTP_410, TLS_CERTIFICATE_ERROR,\nADDRESS_FORBIDDEN, REDIRECT_NOT_FOLLOWED and HTTP_<status> of any other unsupported answer.\nAlso HTTP_400, HTTP_413, HTTP_422 (the update became FAILED), HTTP_429 (slowed down) and\nDISABLED_BY_PLATFORM. Consumers must accept unknown values.\n"
          },
          "message": {
            "type": "string",
            "description": "Sanitised; never contains secrets or message text."
          }
        }
      },
      "DeliveryInfo": {
        "type": "object",
        "required": [
          "mode",
          "config_version",
          "pending_update_count",
          "failed_update_count",
          "maintenance"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "polling",
              "webhook"
            ]
          },
          "config_version": {
            "$ref": "#/components/schemas/Id"
          },
          "pending_update_count": {
            "type": "integer"
          },
          "failed_update_count": {
            "type": "integer"
          },
          "oldest_pending_date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "last_delivery_date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "last_error": {
            "$ref": "#/components/schemas/DeliveryError"
          },
          "confirmed_offset": {
            "$ref": "#/components/schemas/Id",
            "description": "Polling mode."
          },
          "lease": {
            "$ref": "#/components/schemas/Lease",
            "description": "Polling mode, when a consumer holds the lease."
          },
          "webhook": {
            "$ref": "#/components/schemas/WebhookInfo"
          },
          "maintenance": {
            "type": "boolean",
            "description": "True during a technical pause of the platform."
          },
          "retention_seconds": {
            "type": "integer",
            "description": "How long unconfirmed updates are kept (604800 = 7 days)."
          }
        }
      },
      "DeliveryInfoResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/DeliveryInfo"
          }
        }
      },
      "WebhookInfo": {
        "type": "object",
        "required": [
          "url",
          "state",
          "pending_update_count"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "Empty string in polling mode."
          },
          "state": {
            "type": "string",
            "enum": [
              "none",
              "active",
              "paused",
              "circuit_open",
              "disabled_by_platform"
            ],
            "description": "`paused`: waiting for the owner after an answer only the owner can fix (see `last_error`);\nthe owner resumes delivery in \"My bots\". `circuit_open`: repeated failures, SMeet probes\nby itself. `disabled_by_platform`: an administrator turned the webhook off.\n"
          },
          "pending_update_count": {
            "type": "integer"
          },
          "next_attempt_date": {
            "$ref": "#/components/schemas/Timestamp"
          },
          "last_error": {
            "$ref": "#/components/schemas/DeliveryError"
          },
          "max_connections": {
            "type": "integer",
            "const": 1
          }
        }
      },
      "WebhookInfoResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/WebhookInfo"
          }
        }
      },
      "GetMeResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/Bot"
          }
        }
      },
      "Initiator": {
        "type": "object",
        "required": [
          "user_id",
          "role",
          "chat_id"
        ],
        "description": "The person on whose decision the bot acts, and the role they must hold now. Checked in the\nparent group of `chat_id` together with the action; failing it gives 403\nINITIATOR_NOT_AUTHORIZED, the same answer for \"not a member\", \"not the owner\" and \"not known\nto the bot\". An unknown field inside the object gives 400 INVALID_REQUEST.\n",
        "properties": {
          "user_id": {
            "$ref": "#/components/schemas/Id",
            "description": "Usually `callback_query.from.id` or `message.from.id`."
          },
          "role": {
            "type": "string",
            "enum": [
              "group_member",
              "group_owner"
            ],
            "description": "`group_owner`: the group's current owner. `group_member`: a member of the group known to the\nbot there (it received an update from them since the current installation). Both must be\nactive members of the group's space.\n"
          },
          "chat_id": {
            "$ref": "#/components/schemas/Id",
            "description": "A group, topic or channel of this bot. When the method's own chat is a group, the same\ngroup; when it is a private chat, any group of the bot.\n"
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "The installation of the bot in that group."
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "The access revision of the bot's installation in that group."
          }
        }
      },
      "SetMyConditionsModeRequest": {
        "type": "object",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "optional",
              "strict"
            ]
          }
        }
      },
      "GetChatContextRequest": {
        "type": "object",
        "required": [
          "chat_id"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "user_id": {
            "$ref": "#/components/schemas/Id"
          }
        }
      },
      "ChatContext": {
        "type": "object",
        "required": [
          "chat",
          "space"
        ],
        "description": "One chat as it is now. Exactly one of `private` and `group` is present.",
        "properties": {
          "chat": {
            "$ref": "#/components/schemas/Chat",
            "description": "With `access_revision` and, for groups, `installation_generation` of this moment."
          },
          "space": {
            "$ref": "#/components/schemas/Space"
          },
          "private": {
            "$ref": "#/components/schemas/ChatContextPrivate"
          },
          "group": {
            "$ref": "#/components/schemas/ChatContextGroup"
          },
          "user_check": {
            "$ref": "#/components/schemas/UserCheck",
            "description": "Present when `user_id` was passed."
          }
        }
      },
      "ChatContextPrivate": {
        "type": "object",
        "required": [
          "user",
          "status"
        ],
        "properties": {
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "status": {
            "type": "string",
            "enum": [
              "started",
              "stopped",
              "blocked",
              "removed"
            ],
            "description": "As in chat_access_changed, and as sending would find it now: `blocked` also when the\nperson blocked the bot's account in their general block list, `removed` also when they are\nno longer an active member of the bot's space.\n"
          }
        }
      },
      "ChatContextGroup": {
        "type": "object",
        "required": [
          "owner",
          "permissions",
          "installed_at"
        ],
        "properties": {
          "owner": {
            "$ref": "#/components/schemas/User"
          },
          "permissions": {
            "$ref": "#/components/schemas/GroupBotPermissions"
          },
          "installed_at": {
            "$ref": "#/components/schemas/Timestamp",
            "description": "When the current installation began; the bot sees nothing from before it."
          }
        }
      },
      "UserCheck": {
        "type": "object",
        "required": [
          "user_id"
        ],
        "properties": {
          "user_id": {
            "$ref": "#/components/schemas/Id"
          },
          "is_chat_user": {
            "type": "boolean",
            "description": "Private chats only. The person is the one of this chat."
          },
          "known": {
            "type": "boolean",
            "description": "Groups only. The group's owner, or a person the bot received an update from in this group\nsince the current installation (for about 8 days after the last one).\n"
          },
          "is_member": {
            "type": "boolean",
            "description": "Only with `known` true. In the group and an active member of its space."
          },
          "is_owner": {
            "type": "boolean",
            "description": "Only with `known` true. The group's current owner and an active member of its space."
          }
        }
      },
      "ChatContextResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/ChatContext"
          }
        }
      },
      "UploadFileRequest": {
        "type": "object",
        "required": [
          "file"
        ],
        "properties": {
          "file": {
            "type": "string",
            "format": "binary"
          },
          "kind": {
            "type": "string",
            "enum": [
              "photo",
              "document"
            ],
            "default": "document"
          },
          "file_name": {
            "type": "string",
            "maxLength": 255
          }
        }
      },
      "SendFileRequest": {
        "type": "object",
        "required": [
          "chat_id",
          "file_id"
        ],
        "properties": {
          "chat_id": {
            "$ref": "#/components/schemas/Id"
          },
          "file_id": {
            "$ref": "#/components/schemas/FileId",
            "description": "A file this bot uploaded, or an attachment of a message this bot received in the\nsame space. Must be `ready`: otherwise FILE_NOT_READY (retry later with the same\nIdempotency-Key) or FILE_REJECTED.\n"
          },
          "caption": {
            "type": "string",
            "maxLength": 1024
          },
          "reply_to_message_id": {
            "$ref": "#/components/schemas/Id"
          },
          "reply_markup": {
            "$ref": "#/components/schemas/InlineKeyboardMarkup"
          },
          "expected_access_revision": {
            "$ref": "#/components/schemas/Revision",
            "description": "Act only while the chat's `access_revision` is this one; otherwise 409 ACCESS_REVISION_CONFLICT."
          },
          "expected_installation_generation": {
            "$ref": "#/components/schemas/Revision",
            "description": "Groups, topics and channels: act only while the installation is this one; otherwise 409\nINSTALLATION_GENERATION_CONFLICT. In a private chat, 400 INVALID_REQUEST.\n"
          },
          "initiator": {
            "$ref": "#/components/schemas/Initiator"
          }
        }
      },
      "File": {
        "type": "object",
        "required": [
          "file_id",
          "kind",
          "file_name",
          "size",
          "status"
        ],
        "properties": {
          "file_id": {
            "$ref": "#/components/schemas/FileId"
          },
          "kind": {
            "type": "string",
            "enum": [
              "photo",
              "document",
              "voice"
            ]
          },
          "file_name": {
            "type": "string"
          },
          "mime_type": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/FileStatus"
          },
          "reason": {
            "type": "string",
            "description": "For rejected and scan_failed. Values: `malware_detected`, `type_not_allowed` (markup, programs and\nother refused types), `too_large` (a file above the limit is rejected; one the scanner refuses\nfor its size ends as scan_failed), `empty` (no content), `scanner_unavailable`, `scanner_outdated`\n(signatures older than 3 days), `scan_timeout`, `source_missing` (the attachment disappeared\nbefore the check). Consumers must accept unknown values.\n"
          },
          "retry_after": {
            "type": "integer",
            "description": "For scanning; seconds before asking again."
          },
          "download_path": {
            "type": "string",
            "description": "Present only for ready files; relative to the API base, requires the token.",
            "example": "/files/f_Qm9vdGZpbGVfMDAwMDAx/content"
          }
        }
      },
      "FileResponse": {
        "type": "object",
        "required": [
          "ok",
          "result"
        ],
        "properties": {
          "ok": {
            "const": true
          },
          "result": {
            "$ref": "#/components/schemas/File"
          }
        }
      }
    }
  }
}
