机器人开发
Bot API 参考
完整列出 Pabal 的 HTTP Bot API 接受的方法、收发的对象以及错误。与 Telegram Bot API 兼容。
Pabal 的 HTTP Bot API 使用与 Telegram Bot API 相同的地址格式、请求、响应和错误。本文档只列出 Pabal 实际接受的内容。这里没有列出的方法会返回 404 Not Found: method not found。如果你是第一次接触,请先阅读创建机器人教程。
发送请求
https://pabal.me/bot<令牌>/<方法>
- HTTP 方法:
GET和POST都可以。 - 发送参数的四种方式——查询字符串(
?chat_id=1&text=hi)、application/x-www-form-urlencoded、application/json,以及上传文件时的multipart/form-data。也可以混合使用。 - 对象类型的参数(
reply_markup、commands、allowed_updates)在 JSON 正文中直接写成对象或数组,在表单和查询字符串中则写成 JSON 字符串。 - 方法名不区分大小写(
sendMessage=sendmessage)。 - 正文大小上限为 12MB(超过则返回
413)。 - 下载文件使用单独的地址
https://pabal.me/file/bot<令牌>/<file_path>(见 getFile)。
响应与错误
响应始终是 JSON。成功时返回 HTTP 200 和 result;失败时返回相应的 HTTP 状态、与之相同的 error_code,以及供人阅读的 description。
{"ok": true, "result": { … }}{"ok": false, "error_code": 400, "description": "Bad Request: chat not found"}| error_code | 何时出现 | description 示例 |
|---|---|---|
400 | 参数有误 | Bad Request: chat not found, Bad Request: message text is empty, Bad Request: message is not modified: …, Bad Request: message to edit not found, Bad Request: wrong file identifier/HTTP URL specified, Bad Request: query is too old and response timeout expired or query ID is invalid |
401 | 令牌错误 | Unauthorized |
403 | 没有发送权限 | Forbidden: bot can't initiate conversation with a user, Forbidden: bot is not a member of the group chat |
404 | 方法或文件不存在 | Not Found: method not found |
409 | 设置了 Webhook 却调用 getUpdates | Conflict: can't use getUpdates method while webhook is active; use deleteWebhook to delete the webhook first |
413 | 正文超过 12MB | Request Entity Too Large |
500 | 服务器内部错误 | Internal Server Error |
Pabal 目前还没有针对全部请求的频率限制,但语音方法有每小时限额,超过时返回 429 Too Many Requests: retry after N(语音通话)。请把程序写成收到 429 时等待 parameters.retry_after 秒后再重试。
接收更新
从以下两种方式中选择一种。两者不能同时使用。
getUpdates
POST/bot<令牌>/getUpdates
获取正在等待的更新(长轮询)。如果设置了 Webhook,则返回 409。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
offset | Integer | 可选 | 只返回编号大于或等于此值的更新。比它小的更新会作为“已收到”被删除。请传入最后处理的 update_id + 1。 |
limit | Integer | 可选 | 1~100,默认 100 |
timeout | Integer | 可选 | 等待的秒数,0~50,默认 0。建议使用 25~30。 |
allowed_updates | Array of String | 可选 | 要接收的类型(Update)。留空表示全部默认类型(message、edited_message、callback_query)。语音类型只有写出名称才会送达。传入的列表会作为机器人的设置保留,之后的调用和 Webhook 也会使用(不传则保持原值) |
返回值:Array of Update
setWebhook
POST/bot<令牌>/setWebhook
通过 HTTPS 地址接收更新。详细说明请参阅 Webhook 文档。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
url | String | 是 | https:// 公网地址。传入空字符串会删除 Webhook |
secret_token | String | 可选 | 1~256 个字符,A-Z a-z 0-9 _ -。通过请求头 X-Telegram-Bot-Api-Secret-Token 发送 |
allowed_updates | Array of String | 可选 | 从 message、edited_message、callback_query 中选择。留空表示这三种全部。语音类型(voice_call、voice_call_tool_query、voice_call_transcript)只有写出名称才会送达。不传则保持原值 |
drop_pending_updates | Boolean | 可选 | 丢弃正在等待的更新 |
max_connections | Integer | 可选 | 1~100,默认 40。仅保存该值,发送时每个机器人一次只发一个 |
certificate | InputFile | 不支持 | 返回 400——请使用公共证书 |
ip_address | String | 忽略 |
返回值:True
deleteWebhook
POST/bot<令牌>/deleteWebhook
删除 Webhook,回到 getUpdates。即使没有设置 Webhook 也会成功。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
drop_pending_updates | Boolean | 可选 | 丢弃正在等待的更新 |
返回值:True
getWebhookInfo
GET/bot<令牌>/getWebhookInfo
Webhook 的状态。没有参数。没有设置 Webhook 时,url 为空字符串。
返回值:WebhookInfo
方法
| 方法 | 作用 |
|---|---|
getMe | 机器人自身的信息 |
sendMessage | 发送文字(可带按钮) |
sendPhoto | 发送照片 |
sendDocument | 发送文件 |
sendLocation | 发送位置(包括实时位置) |
sendVenue | 发送地点(带名称和地址的位置) |
sendContact | 发送联系人名片 |
editMessageLiveLocation · stopMessageLiveLocation | 移动或停止实时位置 |
editMessageText | 修改已发送消息的文字和按钮 |
editMessageCaption | 修改照片说明 |
editMessageReplyMarkup | 只修改按钮 |
deleteMessage | 删除消息 |
answerCallbackQuery | 回答按钮点击 |
sendChatAction | “正在输入”提示(只接收) |
getChat | 对话信息 |
getFile | 收到的照片的下载路径 |
setMyCommands · getMyCommands · deleteMyCommands | 命令菜单 |
logOut · close | 用于兼容(不执行任何操作) |
getUpdates · setWebhook · deleteWebhook · getWebhookInfo | 接收更新(见上文) |
setVoiceCallSettings · getVoiceCallSettings · endVoiceCall · sendVoiceCallContext · getVoiceCallUsage · startVoiceCall · answerVoiceCallToolQuery · setVoiceCallApiKey · setVoiceCallMcpServer … | 语音机器人(见下文语音通话) |
chat_id 可以填什么
一对一对话时填用户的 ID(正数),普通群组时填群组 ID(负数),或者填用户的用户名("@hana_lee")。这些都可以从更新的 chat.id 中得知。频道和超级群组的 ID(-100…)目前还不存在(400 chat not found)。
getMe
GET/bot<令牌>/getMe
用于确认令牌是否正确。没有参数。
返回值:User——对于机器人,还会额外带上 can_join_groups(true)、can_read_all_group_messages(true)、supports_inline_queries(false)、can_connect_to_business(false)、has_main_web_app(false)。
sendMessage
POST/bot<令牌>/sendMessage
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话(参见上面的提示框) |
text | String | 是 | 1~4,096 个字符。按原样发送文字 |
reply_markup | InlineKeyboardMarkup · ReplyKeyboardMarkup · ReplyKeyboardRemove · ForceReply | 可选 | 按钮 |
disable_notification | Boolean | 可选 | 静默发送 |
parse_mode, entities, reply_parameters, link_preview_options … | 忽略 | 会接收但不使用。不会应用任何格式 |
返回值:发送出去的 Message
要发送给某个用户,该用户必须先与机器人对话过(403 Forbidden: bot can't initiate conversation with a user)。要发送到群组,机器人必须是该群组的成员。
sendPhoto
POST/bot<令牌>/sendPhoto
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话 |
photo | InputFile 或 String | 是 | 用 multipart/form-data 上传的文件(最大 10MB,JPEG、PNG、GIF),或者之前收到的照片的 file_id。暂不支持 URL |
caption | String | 可选 | 0~1,024 个字符 |
reply_markup | 与 sendMessage 相同 | 可选 | |
disable_notification | Boolean | 可选 |
返回值:发送出去的 Message(photo 中带有新的 file_id)
sendDocument
POST/bot<令牌>/sendDocument
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话 |
document | InputFile 或 String | 是 | 用 multipart/form-data 上传的文件(不限格式,最大 20MB),或者之前收到的文件的 file_id。暂不支持 URL |
filename | String | 可选 | 显示给接收方的名称。不填则使用上传文件本身的名称 |
caption | String | 可选 | 0~1,024 个字符 |
reply_markup | 与 sendMessage 相同 | 可选 | |
disable_notification | Boolean | 可选 | |
thumbnail, disable_content_type_detection | 忽略 | 会接收但不使用 |
返回值:发送出去的 Message(document 中带有新的 file_id)
格式(mime_type)根据文件名的扩展名确定。从应用发送的文件最大 2GB,但机器人通过 HTTP 上传和下载的上限与 Telegram 一样,为 20MB。
sendLocation
POST/bot<令牌>/sendLocation
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话 |
latitude, longitude | Float | 是 | 纬度(−90~90)和经度(−180~180)。超出范围时返回 400 Bad Request: GEO_POINT_INVALID |
horizontal_accuracy | Float | 可选 | 误差半径(米,0~1,500)。四舍五入后以整数保存 |
live_period | Integer | 可选 | 填写后即为实时位置:60~86,400 秒,或填 2147483647(0x7FFFFFFF)表示直到停止。其他值返回 400 Bad Request: wrong live_period |
heading | Integer | 可选 | 实时位置的行进方向,1~360 度 |
proximity_alert_radius | Integer | 可选 | 实时位置的接近提醒半径(米)。会保存并显示,但目前还不会发送提醒 |
reply_markup | 与 sendMessage 相同 | 可选 | |
disable_notification | Boolean | 可选 |
返回值:发送出去的 Message(location 中带有 Location)
sendVenue
POST/bot<令牌>/sendVenue
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话 |
latitude, longitude | Float | 是 | 地点的位置(与 sendLocation 相同) |
title | String | 是 | 地点名称 |
address | String | 是 | 地址 |
foursquare_id, foursquare_type | String | 可选 | Foursquare 的地点 ID 和类型,按收到的原样传递 |
google_place_id, google_place_type | String | 可选 | Google 的地点 ID 和类型。仅在没有 foursquare_id 时使用 |
reply_markup | 与 sendMessage 相同 | 可选 | |
disable_notification | Boolean | 可选 |
返回值:发送出去的 Message(venue 中带有 Venue,location 中也有同一位置)
缺少 title 或 address 时返回 400 Bad Request: title and address are required。
sendContact
POST/bot<令牌>/sendContact
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 发送到的对话 |
phone_number | String | 是 | 电话号码,按填写的原样传递 |
first_name | String | 是 | 名 |
last_name | String | 可选 | 姓 |
vcard | String | 可选 | vCard 格式的附加信息,最多 64KB |
reply_markup | 与 sendMessage 相同 | 可选 | |
disable_notification | Boolean | 可选 |
返回值:发送出去的 Message(contact 中带有 Contact)
机器人发送的联系人名片不会带 user_id,即使该号码属于某个 Pabal 账号也是如此——机器人没有联系人;如果填上,机器人只要每个号码发一张名片,就能查出号码属于谁。缺少 phone_number 或 first_name 时返回 400 Bad Request: phone_number and first_name are required。
editMessageLiveLocation
POST/bot<令牌>/editMessageLiveLocation
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 消息所在的对话 |
message_id | Integer | 是 | 要移动的实时位置(机器人发送的) |
latitude, longitude | Float | 是 | 新的位置 |
horizontal_accuracy | Float | 可选 | 误差半径(米,0~1,500) |
heading | Integer | 可选 | 行进方向,1~360 度 |
proximity_alert_radius | Integer | 可选 | 接近提醒半径(米)。填 0 则关闭 |
live_period | Integer | 可选 | 新的共享时长:从消息发送时刻起算的秒数。最多只能比当前时长多延长一天;填 2147483647 表示直到停止 |
reply_markup | InlineKeyboardMarkup | 可选 | 新的按钮 |
inline_message_id | String | 不支持 | 没有内联模式,因此返回 400 |
返回值:修改后的 Message
已经结束的实时位置——已停止或时长已到——既不能移动,也不能通过延长时长使其恢复(400 Bad Request: message can't be edited)。不是实时位置的消息也一样。
距上一次生效的移动不足 10 秒,或移动距离不足 10 米的移动,服务器不会保存,直接略过。停止以及时长、提醒半径的变更则总会生效。被略过时,返回的 Message 显示最后一次生效的位置,因此每隔几秒发送一次也没有问题。
stopMessageLiveLocation
POST/bot<令牌>/stopMessageLiveLocation
参数为 chat_id、message_id、reply_markup(可选)。让实时位置停在最后的位置。共享时长会缩短为实际经过的时间,因此所有应用都会把它显示为已结束。如果已经停止或结束,返回 400 Bad Request: message is not modified: …。返回值:修改后的 Message。
editMessageText
POST/bot<令牌>/editMessageText
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chat_id | Integer 或 String | 是 | 消息所在的对话 |
message_id | Integer | 是 | 要修改的消息(机器人发送的) |
text | String | 是 | 新的文字,1~4,096 个字符 |
reply_markup | InlineKeyboardMarkup | 可选 | 新的按钮。省略时按钮会被移除(与 Telegram 相同) |
inline_message_id | String | 不支持 | 没有内联模式,因此返回 400 |
返回值:修改后的 Message。修改会立即反映到应用中;用户修改的消息则会以 edited_message 发给机器人。
文字和按钮与之前完全相同时,返回 400 Bad Request: message is not modified: …;试图修改别人的消息时,返回 400 Bad Request: message can't be edited。
editMessageCaption
POST/bot<令牌>/editMessageCaption
参数为 chat_id、message_id、caption(0~1,024 个字符,省略则删除说明)、reply_markup。返回值:修改后的 Message。
editMessageReplyMarkup
POST/bot<令牌>/editMessageReplyMarkup
保持文字不变,只更换按钮。参数为 chat_id、message_id、reply_markup(省略则删除按钮)。返回值:修改后的 Message。
deleteMessage
POST/bot<令牌>/deleteMessage
参数为 chat_id、message_id。在对话双方那里都删除该消息。消息不存在时返回 400 Bad Request: message to delete not found。返回值:True。
answerCallbackQuery
POST/bot<令牌>/answerCallbackQuery
回答用户点击的按钮(CallbackQuery)。必须在 10 秒内回答,且只能回答一次。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
callback_query_id | String | 是 | 更新中的 callback_query.id |
text | String | 可选 | 在屏幕上方短暂显示的文字 |
show_alert | Boolean | 可选 | 为 true 时显示为带确认按钮的对话框 |
url | String | 可选 | 让应用打开的地址 |
cache_time | Integer | 可选 | 应用缓存此回答的秒数 |
返回值:True。如果为时已晚或已经回答过,返回 400 Bad Request: query is too old and response timeout expired or query ID is invalid。
sendChatAction
POST/bot<令牌>/sendChatAction
为了兼容会接收请求并返回 True,但目前还不会在应用中显示“正在输入…”。
getChat
GET/bot<令牌>/getChat?chat_id=…
参数为 chat_id(数字)。如果是用户,就返回该用户;如果是群组,则仅限机器人是其成员的群组。返回值:Chat。不存在或无权查看时,返回 400 Bad Request: chat not found。
getFile
GET/bot<令牌>/getFile?file_id=…
用收到的照片的 file_id 获取下载路径。返回值:File。然后通过下面的地址下载。
https://pabal.me/file/bot<令牌>/<file_path>
file_id 同时也是取得该照片的凭证。值无效时,返回 400 Bad Request: wrong file identifier/HTTP URL specified。
setMyCommands
POST/bot<令牌>/setMyCommands
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
commands | Array of BotCommand | 是 | 最多 100 条 |
language_code | String | 可选 | 保存为该语言的列表。目前应用中只显示未指定语言代码的默认列表 |
scope | BotCommandScope | 忽略 |
返回值:True。不符合规则时什么也不保存,返回 400 Bad Request: BOT_COMMAND_INVALID(命令)、BOT_COMMAND_DESCRIPTION_INVALID(说明为空或超过 256 个字符)、BOT_COMMANDS_TOO_MUCH(超过 100 个)。
getMyCommands
GET/bot<令牌>/getMyCommands
参数为 language_code(可选)。返回值:Array of BotCommand。
deleteMyCommands
POST/bot<令牌>/deleteMyCommands
参数为 language_code(可选)。清空该列表。返回值:True。
logOut · close
在 Telegram 中,这两个方法用于迁移到本地 Bot API 服务器。Pabal 没有可以迁移的目标,因此只会接收请求并返回 True。要让令牌失效,请使用 BotFather 的 /revoke。
对象
字段旁边的 可选 表示该字段可能不存在。这里没有列出的 Telegram 其他字段,Pabal 不会发送。
Update
一条新的更新。包含 update_id 以及下面各项中的一个。
| 字段 | 类型 | 说明 |
|---|---|---|
update_id | Integer | 逐次加 1 的编号。用于 getUpdates 的 offset |
message 可选 | Message | 发给机器人的新消息(一对一对话,或机器人所在群组中的所有消息) |
edited_message 可选 | Message | 被修改的消息 |
callback_query 可选 | CallbackQuery | 内联按钮点击 |
voice_call 可选 | VoiceCall | 打给语音机器人的通话和机器人打出的电话的开始和结束(需要按名称请求才会送达) |
voice_call_tool_query 可选 | VoiceCallToolQuery | 通话中模型调用的机器人工具(需要按名称请求才会送达) |
voice_call_transcript 可选 | VoiceCallTranscript | 通话中文字记录的一段发言(需要按名称请求才会送达) |
User
| 字段 | 类型 | 说明 |
|---|---|---|
id | Integer | 用户 ID(只在这台服务器内有意义) |
is_bot | Boolean | 机器人为 true |
first_name | String | 名字。已删除的账号为 Deleted Account |
last_name 可选 | String | 姓氏 |
username 可选 | String | 用户名(不带 @) |
Chat
| 字段 | 类型 | 说明 |
|---|---|---|
id | Integer | 用户为该用户的 ID(正数),普通群组为负数 |
type | String | private 或 group |
title 可选 | String | 群组名称(group) |
first_name, last_name, username 可选 | String | 对方的名字和用户名(private) |
Message
| 字段 | 类型 | 说明 |
|---|---|---|
message_id | Integer | 该对话中的消息编号 |
from 可选 | User | 发送者 |
chat | Chat | 消息所在的对话 |
date | Integer | 发送时间(Unix 秒) |
edit_date 可选 | Integer | 最后一次修改的时间 |
text 可选 | String | 文字(不是照片、文件、位置、地点或联系人消息时总会有) |
entities 可选 | Array of MessageEntity | 文字中的命令、提及、URL、话题标签 |
photo 可选 | Array of PhotoSize | 照片(Pabal 只有一张原图) |
document 可选 | Document | 文件 |
location 可选 | Location | 位置或实时位置。地点消息的位置也会一并放在这里 |
venue 可选 | Venue | 地点 |
contact 可选 | Contact | 联系人名片 |
caption 可选 | String | 照片说明 |
caption_entities 可选 | Array of MessageEntity | 说明中的命令、提及、URL、话题标签 |
reply_markup 可选 | InlineKeyboardMarkup | 消息上附带的内联按钮 |
MessageEntity
| 字段 | 类型 | 说明 |
|---|---|---|
type | String | bot_command, mention, url, hashtag |
offset | Integer | 起始位置(UTF-16 代码单元) |
length | Integer | 长度(UTF-16 代码单元) |
由服务器在文字中自动识别并附上。粗体、斜体等格式实体目前还没有。
PhotoSize
| 字段 | 类型 | 说明 |
|---|---|---|
file_id | String | 用于下载(getFile)和再次发送(sendPhoto)的 ID |
file_unique_id | String | 同一张照片即使在不同机器人那里也是相同的值。不能用于下载 |
width, height | Integer | 像素尺寸 |
file_size | Integer | 字节数 |
Document
| 字段 | 类型 | 说明 |
|---|---|---|
file_id | String | 用于下载(getFile)和再次发送(sendDocument)的 ID |
file_unique_id | String | 同一个文件即使在不同机器人那里也是相同的值。不能用于下载 |
file_name | String | 发送方给出的名称 |
mime_type | String | 发送方声明的格式 |
file_size | Integer | 字节数 |
Location
| 字段 | 类型 | 说明 |
|---|---|---|
latitude, longitude | Float | 纬度和经度 |
horizontal_accuracy 可选 | Float | 误差半径(米) |
live_period 可选 | Integer | 实时位置的共享时长:从消息发送时刻起算的秒数。停止后会缩短为实际经过的时间 |
heading 可选 | Integer | 行进方向,1~360 度 |
proximity_alert_radius 可选 | Integer | 接近提醒半径(米) |
用户共享的实时位置,每当服务器应用一次移动,都会以 edited_message 再次送达。
Venue
| 字段 | 类型 | 说明 |
|---|---|---|
location | Location | 地点的位置 |
title | String | 地点名称 |
address | String | 地址 |
foursquare_id, foursquare_type 可选 | String | Foursquare 的地点 ID 和类型 |
google_place_id, google_place_type 可选 | String | Google 的地点 ID 和类型 |
Contact
| 字段 | 类型 | 说明 |
|---|---|---|
phone_number | String | 发送者填写的原样号码 |
first_name | String | 名 |
last_name 可选 | String | 姓 |
user_id 可选 | Integer | 该号码对应的 Pabal 账号。仅当发送者已把此人保存在自己的联系人中,或者就是本人时才会带上 |
vcard 可选 | String | vCard 格式的附加信息 |
File
| 字段 | 类型 | 说明 |
|---|---|---|
file_id, file_unique_id | String | 与 PhotoSize 相同 |
file_size | Integer | 字节数 |
file_path | String | photos/<file_id>.jpg 或 documents/<file_id> 形式。接在 /file/bot<令牌>/ 后面即可下载 |
CallbackQuery
| 字段 | 类型 | 说明 |
|---|---|---|
id | String | 传给 answerCallbackQuery 的 ID |
from | User | 点击按钮的用户 |
message 可选 | Message | 附带该按钮的消息 |
chat_instance | String | 代表该对话的值 |
data 可选 | String | 按钮的 callback_data |
InlineKeyboardMarkup
inline_keyboard:Array of Array of InlineKeyboardButton——外层数组是行,内层数组是一行中的按钮。一条消息最多 100 行、100 个按钮。
InlineKeyboardButton
| 字段 | 类型 | 说明 |
|---|---|---|
text | String | 按钮上的文字 |
callback_data 二选一 | String | 点击后发给机器人的值,1~64 字节 |
url 二选一 | String | 点击后打开的地址 |
switch_inline_query、web_app、login_url、pay 等其他类型目前还没有(400)。
ReplyKeyboardMarkup
| 字段 | 类型 | 说明 |
|---|---|---|
keyboard | Array of Array of KeyboardButton | 输入框下方的按钮面板 |
resize_keyboard, one_time_keyboard, is_persistent, selective 可选 | Boolean | 自动调整大小 · 使用一次后隐藏 · 始终显示 · 只对特定用户显示 |
input_field_placeholder 可选 | String | 输入框中的提示文字 |
KeyboardButton
一个字符串,或者一个包含 text 以及可选字段 request_contact(发送我的联系方式)、request_location(发送我的位置,Boolean)的对象。
ReplyKeyboardRemove
{"remove_keyboard": true}——隐藏按钮面板。selective 可选。
ForceReply
{"force_reply": true}——应用会以回复这条消息的状态打开输入框。selective、input_field_placeholder 可选。
BotCommand
| 字段 | 类型 | 说明 |
|---|---|---|
command | String | 1~32 个小写英文字母、数字和下划线(不带 /) |
description | String | 1~256 个字符 |
WebhookInfo
| 字段 | 类型 | 说明 |
|---|---|---|
url | String | Webhook 地址,没有则为空字符串 |
has_custom_certificate | Boolean | 始终为 false |
pending_update_count | Integer | 等待送达的更新数量 |
ip_address 可选 | String | 最近一次发送的目标 IP |
last_error_date 可选 | Integer | 最后一次失败的时间(Unix 秒) |
last_error_message 可选 | String | 最后一次失败的原因(列表) |
max_connections 可选 | Integer | 在 setWebhook 中传入的值 |
allowed_updates 可选 | Array of String | 在 setWebhook 中传入的值 |
语音通话
这些方法只有 Pabal 才有。语音机器人是指有人在应用中给它打电话时由 AI 语音模型接听的机器人,这些方法用来设定该模型的设置并处理通话。需要开启哪些条件、如何开启以及示例,请参阅语音机器人指南。即使服务器上关闭了语音,这些方法也依然存在,可以读取设置;但语音已关闭或尚未获得运营方允许的机器人,除了关闭和删除之外不能修改设置(403 VOICE_NOT_AVAILABLE)。
setVoiceCallSettings
POST/bot<令牌>/setVoiceCallSettings
修改机器人的语音设置。只修改所发送的字段;先检查全部内容,然后一次写入,或者全部拒绝。每个机器人每小时 30 次(与 @BotFather 合计)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | Boolean | 可选 | 只有在 @BotFather 中同意语音机器人规则后才能开启(403 VOICE_RULES_NOT_ACCEPTED)。关闭随时可以 |
instructions | String | 可选 | 模型的指令,最多 8,192 字节。"" 表示删除(已开启的托管机器人不行) |
greeting | String | 可选 | 第一句问候,最多 512 字节。为 "" 时由模型自行决定 |
voice | String | 可选 | 音色 id,默认 kore(列表) |
language | String | 可选 | ko-KR(默认)、en-US、ja-JP、cmn-CN、fr-FR、es-US、id-ID、vi-VN、ar-EG(列表)。不区分大小写,zh-CN 会保存为 cmn-CN。韩语、英语以外的机器人要等运营方阅读指令和问候语并允许后才会接听电话 |
max_call_duration | Integer | 可选 | 秒,60 ~ limits.max_call_duration |
max_concurrent_calls | Integer | 可选 | 1 ~ limits.max_concurrent_calls |
tools | Array of VoiceCallTool | 可选 | 通话中模型调用的机器人工具:{"name", "description", "parameters"?, "timeout_ms"?}。规则见定义工具。表单中为 JSON 字符串 |
transcript | Boolean | 可选 | 文字记录开关。只有同意机器人所有者条款后才能开启 |
mode | String | 可选 | managed(Pabal 的 AI 模型)或 stream(音频流模式) |
stream_url, stream_secret | String | 可选 | 与 mode=stream 一起使用。机密值只能放在请求体中 |
返回值:True
getVoiceCallSettings
GET/bot<令牌>/getVoiceCallSettings
没有参数。返回当前设置、机器人现在能否接听电话(available、unavailable_reason)、服务器的限额、音色和语言列表、工具查询和文字记录的去向,以及自有密钥、音频流模式和 MCP 服务器的状态。不显示密钥和机密值,只显示指纹。字段见语音机器人——查看当前设置。
返回值:VoiceCallSettings(对象)
endVoiceCall
POST/bot<令牌>/endVoiceCall
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
voice_call_id | String | 是 | voice_call.id |
farewell | Boolean | 可选 | 默认 true:模型简短道别后挂断(10 秒内没挂断则由服务器结束)。为 false 时立即挂断 |
返回值:True。如果不是这个机器人正在进行的通话,返回 400 VOICE_CALL_NOT_FOUND。
sendVoiceCallContext
POST/bot<令牌>/sendVoiceCallContext
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
voice_call_id | String | 是 | 已接通的通话 |
text | String | 是 | 机器人所有者给模型的备注。最多 2,000 个字符、6,144 字节,按内容规则检查 |
respond | Boolean | 可选 | 默认 false。为 true 时模型立即回应 |
返回值:True。接通前返回 VOICE_CALL_NOT_ACTIVE,音频流通话返回 VOICE_CONTEXT_NOT_SUPPORTED,过长返回 VOICE_CONTEXT_TOO_LONG,每通电话每分钟超过 10 条返回 429。
getVoiceCallUsage
GET/bot<令牌>/getVoiceCallUsage
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
period | String | 可选 | today(默认)或 month |
month | String | 可选 | YYYY-MM,只能与 period=month 一起使用 |
返回值:period、from_date、to_date、calls、seconds、missed、refused(busy·budget·unavailable)、platform_seconds、own_key_seconds、remaining_seconds_today(bot·owner),曾开启过外呼的机器人还有 outbound(today·limits)——日期分界以服务器的时区为准
startVoiceCall
POST/bot<令牌>/startVoiceCall
机器人给人打电话。只有机器人所有者在 @BotFather 中开启、并经运营方审核的机器人,才能打给许可了该机器人的人。回答和判定见语音机器人——拨打。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
user_id | Integer | 是 | 要拨打的人 |
purpose | String | 是 | reminder、wake_up、delivery、appointment 中机器人选择的一个 |
context | String | 是 | 只给模型的说明,最多 1,000 个字符、3,072 字节,按内容规则检查 |
max_duration | Integer | 可选 | 接听后的最长秒数,30–300(不超过机器人的上限)。默认 180 |
ring_timeout | Integer | 可选 | 响铃秒数,30–45。默认 40 |
返回值:{"voice_call_id": "…"}——只表示已受理,是否响铃、是否接听以 voice_call 更新告知。拒绝:403 VOICE_OUTBOUND_OFF: <原因>、403 USER_UNAVAILABLE(响应体始终相同)、429、503 VOICE_UNAVAILABLE。不能通过 Webhook 响应调用。
answerVoiceCallToolQuery
POST/bot<令牌>/answerVoiceCallToolQuery
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
tool_query_id | String | 是 | VoiceCallToolQuery 的 id |
result | String · Object · Array | 二选一 | 工具的结果,最多 16,384 字节 |
error | String | 二选一 | 机器人的失败说明,最多 512 字节 |
返回值:True。第一次回答就是最终回答。太晚时返回 400 TOOL_QUERY_EXPIRED: answered|timeout|cancelled|call_ended|unreachable,未知的 id 返回 TOOL_QUERY_ID_INVALID,回答被拒绝时返回 TOOL_RESULT_EMPTY·TOOL_RESULT_INVALID·TOOL_RESULT_TOO_LONG·TOOL_ERROR_TOO_LONG·TOOL_RESULT_REFUSED: <代码>。对 Webhook 的工具查询 POST,也可以用响应体回答。
setVoiceCallApiKey · deleteVoiceCallApiKey
POST/bot<令牌>/setVoiceCallApiKey
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
provider | String | 是 | google(Vertex AI 服务账号 JSON 密钥)或 openai(sk-…) |
api_key | String | 是 | 密钥。只能放在请求体中(放在查询中返回 400),最多 8KiB |
返回值:True——只有通过网关的测试会话后才会保存。API_KEY_INVALID、API_KEY_NO_REALTIME_ACCESS、503 API_KEY_CHECK_UNAVAILABLE(不保存)、403 VOICE_OWN_KEY_NOT_AVAILABLE(这台服务器不接受自有密钥)。deleteVoiceCallApiKey 没有参数,始终返回 True。这两个方法都不能用 bots.sendCustomRequest 调用,setVoiceCallApiKey 也不能在 Webhook 响应中调用。详见自有模型密钥。
MCP 服务器方法
| 方法 | 参数 | 返回值 |
|---|---|---|
setVoiceCallMcpServer | label、url、auth(对象),可选 audience、allowed_tools、requested_level、timeout_ms、tools(覆盖分类)、declaration、auto_repin | 注册结果(status、job_id)。接收方发生变化时返回 400 MCP_CHANGE_NEEDS_CONFIRMATION,之后需在 @BotFather 中确认 |
refreshVoiceCallMcpServer | label | 重新检查(refreshing: true、job_id) |
deleteVoiceCallMcpServer | label | True——即使 MCP 已关闭也可以 |
getVoiceCallMcpBinding | 无 | iss、sub(bot:<id>)、issuer_document、jwks_uri、audiences |
createVoiceCallMcpClientKey | label | 公开的 jwk、thumbprint(私钥不会离开 Pabal) |
auth 和机密值只能放在请求体中发送。在关闭了 MCP 的服务器上返回 403 VOICE_NOT_AVAILABLE: MCP tools are not available on this server。详见语音机器人——MCP 服务器。
如何接收语音更新
voice_call、voice_call_tool_query、voice_call_transcript 只有按名称请求才会送达——请把它们写进 getUpdates 或 setWebhook 的 allowed_updates。传空列表收不到,请求之前发生的也不会保留。有 Webhook 时,工具查询以单独的 POST 送达;最近 15 秒内调用过 getUpdates 时,则放在下一次 getUpdates 的最前面。
VoiceCall
| 字段 | 类型 | 说明 |
|---|---|---|
id | String | 通话 id(无符号十进制数) |
direction | String | incoming(打给机器人的电话)或 outgoing(机器人打出的电话)。总是存在 |
event | String | started、ended、missed、refused;机器人打出的电话为 started、ended、not_answered、failed |
from 可选 | User | 仅限打给机器人的电话——来电者:id、is_bot、first_name、last_name、language_code。没有用户名和手机号码 |
to 可选 | Object | 仅限机器人打出的电话——{"id": …},只有接听者的 ID |
purpose 可选 | String | 仅限机器人打出的电话——请求的目的 |
date | Integer | 发生的时间(Unix 秒)。started 对应用的通话是密钥交换完成时,对 Apple Watch 的通话是手表的声音接通时。在等待文字记录或开启了保存对话的服务器上,ended 最多会晚 10 秒送达。机器人打出的电话则无论服务器如何设置,接听后的 ended 都要等待网关的用量,最多晚 10 秒送达 |
max_duration 可选 | Integer | 这通电话的最长时间(秒)——started、ended |
start_date, duration 可选 | Integer | 接通时间和通话秒数(服务器时钟)——ended |
end_reason 可选 | String | caller(机器人打出的电话为 callee)、bot、max_length、failed、operator、suspended——ended、missed |
refused_reason 可选 | String | busy、budget、unavailable——refused |
transcript 可选 | Object | {"turns": [{"role", "text", "offset_ms"}], "truncated"}——ended,开启了文字记录时。机器人打出的电话没有 |
VoiceCall 中没有告诉你来电者是否选择了保存对话的字段。这是有意为之——那些文字属于来电者本人,不会发给机器人。因此,在开启了保存对话的服务器上,所有非音频流模式通话的 ended 都会等待同样的时间,而且在所有通话中,通话记录之后那条消息的编号都比记录大 31 以上(编号会预先占用)。
VoiceCallToolQuery
| 字段 | 类型 | 说明 |
|---|---|---|
id | String | 传给 answerVoiceCallToolQuery 的 id |
voice_call_id | String | 通话 id |
from | User | 来电者(字段与 VoiceCall 相同) |
name | String | 工具名 |
arguments | String | 参数,JSON 对象的文本(服务器已检查) |
budget_ms | Integer | 从收到时起,到回答必须送达服务器为止的毫秒数 |
VoiceCallTranscript
| 字段 | 类型 | 说明 |
|---|---|---|
voice_call_id | String | 通话 id |
seq | Integer | 发言编号 |
role | String | caller 或 bot |
text | String | AI 写下的文字。含有银行卡号或居民登记号时,数字会变成 * |
is_final | Boolean | 始终为 true |
offset_ms, date | Integer | 从通话声音开始时算起的毫秒数,以及时间 |
只通过 HTTP Bot API 送达。整通电话的内容在已结束的 voice_call 的 transcript 中。
音频流模式(mode=stream)
在音频流模式下,通话声音不是发给 Pabal 的 AI 模型,而是发给机器人所有者的服务器。向 setVoiceCallSettings 发送 mode=stream、stream_url=wss://…、stream_secret=…(32~128 个可打印 ASCII 字符,只能放在请求体中)后,Pabal 的网关会试着连接一次该地址(探测),成功后开启。需要机器人所有者条款,以及包含音频流确认窗口的应用版本。设置、探测结果和示例见语音机器人——音频流模式。
- 连接:TLS 1.2 及以上,与 URL 中名称相符的公共证书,子协议
pabal.voice.v1,不压缩,每条消息最多 64KiB、文本最多 4KiB,不重定向。 - 签名:
X-Pabal-Voice-Signature: t=…,nonce=…,call=…,v1=HMAC-SHA256(stream_secret, "pabal-voice-stream/1\n<t>\n<nonce>\n<call>\n<host>\n<path?query>")。host是你提供的 URL 的主机。需检查 300 秒、nonce 只用一次、逐字节比较,以及start.call_id是否与call相同(详见)。 - 声音:文本消息是 JSON 事件,二进制是 PCM16 小端序、单声道、24 kHz。来电者的声音为 20 ms(960 字节)的分片。
- Pabal → 机器人:
start(一次) ·live(AI 提示已结束) · 声音 ·mark·cleared·buffer_full·stop(→ 以 1000 关闭)。 - 机器人 → Pabal:
ready(start之后 3 秒内,最先发送) · 声音(live之后) ·clear·mark·hangup。
每条消息的具体格式见语音机器人——规范中的表格。
语音方法的错误
语音方法的错误代码及含义汇总在语音机器人——错误中。403 的形式为 Forbidden: <代码>: <说明>(VOICE_RULES_NOT_ACCEPTED、VOICE_NOT_AVAILABLE、VOICE_SUSPENDED、VOICE_OWNER_TERMS_NOT_ACCEPTED、VOICE_OWN_KEY_NOT_AVAILABLE、VOICE_STREAM_NOT_AVAILABLE、VOICE_OUTBOUND_OFF),只有 USER_UNAVAILABLE 不带说明,始终是 Forbidden: USER_UNAVAILABLE;超过每小时限额时返回 429 和 retry_after。
与 Telegram Bot API 的不同之处
- 更新类型:只有
message、edited_message、callback_query,以及 Pabal 独有的语音机器人类型(voice_call、voice_call_tool_query、voice_call_transcript)。没有频道帖子、内联查询、支付、投票、成员变更(my_chat_member)等。 - 格式:忽略
parse_mode和entities,按原样发送文字。只有命令、提及、URL、话题标签会自动显示。 - 对话类型:只有一对一对话和普通群组。没有频道、超级群组和论坛话题。
- 媒体:只有照片、文件(
sendDocument)以及位置、实时位置、地点和联系人。没有能作为视频或语音播放的消息,也没有贴纸、相册(sendMediaGroup)和投票,不能通过 URL 发送。通过 HTTP 上传和下载的上限为 20MB。 - 位置:实时位置的接近提醒(
proximity_alert_radius)只保存,从不发送。10 秒、10 米以内的移动会被略过而不生效;机器人发送的联系人名片不带user_id。 - 群组中的机器人:没有隐私模式,会收到群组中的所有消息。
- 队列:尚未取走的更新,每个机器人最多在内存中保留最近 1,000 条,服务器重启时会丢失(Telegram 保留 24 小时)。
- Webhook:一次发送一个、按顺序发送(
max_connections只做保存),不接受自签名证书,没有端口限制。 - ID:用户、消息、文件的 ID 只在这台服务器内有意义。由于没有频道和超级群组,也没有
-100…形式的 ID。 - 不存在的方法:上面列表中没有的方法(
forwardMessage、copyMessage、sendVideo、sendPoll、getChatMember、banChatMember、answerInlineQuery…)会返回404 Not Found: method not found。