Docs para desarrolladores
Español

Desarrollo de bots

Referencia de la Bot API

Todos los métodos que acepta la Bot API HTTP de Pabal, los objetos que intercambia y sus errores, sin omitir nada. Compatible con la Bot API de Telegram.

La Bot API HTTP de Pabal usa el mismo formato de direcciones, peticiones, respuestas y errores que la Bot API de Telegram. Este documento recoge solo lo que Pabal acepta de verdad. Los métodos que no aparecen aquí devuelven 404 Not Found: method not found. Si es tu primera vez, empieza por el tutorial para crear un bot.

Enviar peticiones

https://pabal.me/bot<token>/<método>
  • Método HTTP: se admiten tanto GET como POST.
  • Hay cuatro formas de enviar los parámetros: cadena de consulta (?chat_id=1&text=hi), application/x-www-form-urlencoded, application/json y, cuando subes archivos, multipart/form-data. Se pueden combinar.
  • Los parámetros de tipo objeto (reply_markup, commands, allowed_updates) van tal cual, como objeto o array, en un cuerpo JSON, y como cadena JSON en formularios y cadenas de consulta.
  • El nombre del método no distingue entre mayúsculas y minúsculas (sendMessage = sendmessage).
  • El tamaño del cuerpo puede llegar a 12 MB (por encima, 413).
  • La descarga de archivos usa otra dirección: https://pabal.me/file/bot<token>/<file_path> (getFile).

Respuestas y errores

La respuesta siempre es JSON. Si todo va bien, llega un HTTP 200 con result; si falla, llega el estado HTTP correspondiente, un error_code igual a ese estado y una description legible para personas.

{"ok": true, "result": { … }}
{"ok": false, "error_code": 400, "description": "Bad Request: chat not found"}
error_codeCuándoEjemplos de description
400Un parámetro es incorrectoBad 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
401El token es incorrectoUnauthorized
403No hay permiso para enviarForbidden: bot can't initiate conversation with a user, Forbidden: bot is not a member of the group chat
404Método o archivo inexistenteNot Found: method not found
409getUpdates con un webhook configuradoConflict: can't use getUpdates method while webhook is active; use deleteWebhook to delete the webhook first
413El cuerpo supera los 12 MBRequest Entity Too Large
500Error interno del servidorInternal Server Error

Pabal todavía no aplica un límite de frecuencia al conjunto de las peticiones, pero los métodos de voz tienen un límite por hora y pueden devolver 429 Too Many Requests: retry after N (Llamadas de voz). Prepara tu código para que, si recibe un 429, espere parameters.retry_after segundos antes de volver a enviar.

Recibir actualizaciones

Se usa uno de estos dos modos. No se pueden usar los dos a la vez.

getUpdates

POST/bot<token>/getUpdates

Recoge las actualizaciones pendientes (long polling). Si hay un webhook configurado, 409.

ParámetroTipoObligatorioDescripción
offsetIntegerOpcionalSolo las actualizaciones con este número o superior. Las anteriores se borran como «recibidas». Pasa el update_id + 1 del último que procesaste.
limitIntegerOpcionalDe 1 a 100, 100 por defecto
timeoutIntegerOpcionalSegundos de espera, de 0 a 50, 0 por defecto. Se recomienda entre 25 y 30.
allowed_updatesArray of StringOpcionalTipos que quieres recibir (Update). Si está vacío, todos los tipos predeterminados (message, edited_message, callback_query). Los tipos de voz solo llegan si los nombras. La lista que das queda guardada como ajuste del bot y se usa también en las llamadas siguientes y en el webhook (si no das ninguna, se mantiene la anterior)

Devuelve: Array of Update

setWebhook

POST/bot<token>/setWebhook

Recibe las actualizaciones en una dirección HTTPS. La explicación detallada está en el documento Webhooks.

ParámetroTipoObligatorioDescripción
urlStringSíDirección pública https://. Una cadena vacía elimina el webhook
secret_tokenStringOpcionalDe 1 a 256 caracteres, A-Z a-z 0-9 _ -. Se envía en la cabecera de la petición X-Telegram-Bot-Api-Secret-Token
allowed_updatesArray of StringOpcionalEntre message, edited_message y callback_query. Si se deja vacío, esos tres. Los tipos de voz (voice_call, voice_call_tool_query, voice_call_transcript) solo llegan si los nombras. Si no das ninguna lista, se mantiene la anterior
drop_pending_updatesBooleanOpcionalDescarta las actualizaciones pendientes
max_connectionsIntegerOpcionalDe 1 a 100, 40 por defecto. Solo se guarda; la entrega es de una en una por bot
certificateInputFileNo admitido400: usa un certificado público
ip_addressStringSe ignora

Devuelve: True

deleteWebhook

POST/bot<token>/deleteWebhook

Elimina el webhook y vuelve a getUpdates. Tiene éxito aunque no haya webhook.

ParámetroTipoObligatorioDescripción
drop_pending_updatesBooleanOpcionalDescarta las actualizaciones pendientes

Devuelve: True

getWebhookInfo

GET/bot<token>/getWebhookInfo

Estado del webhook. Sin parámetros. Si no hay webhook, url es una cadena vacía.

Devuelve: WebhookInfo

Métodos

MétodoQué hace
getMeInformación del propio bot
sendMessageEnviar texto (con botones)
sendPhotoEnviar una foto
sendDocumentEnviar un archivo
sendLocationEnviar una ubicación (también en tiempo real)
sendVenueEnviar un lugar (una ubicación con nombre y dirección)
sendContactEnviar una tarjeta de contacto
editMessageLiveLocation · stopMessageLiveLocationMover o detener una ubicación en tiempo real
editMessageTextEditar el texto y los botones de un mensaje enviado
editMessageCaptionEditar el pie de una foto
editMessageReplyMarkupEditar solo los botones
deleteMessageBorrar un mensaje
answerCallbackQueryResponder a la pulsación de un botón
sendChatActionIndicador «escribiendo» (solo se acepta)
getChatInformación de un chat
getFileRuta de descarga de una foto recibida
setMyCommands · getMyCommands · deleteMyCommandsMenú de comandos
logOut · closePor compatibilidad (no hacen nada)
getUpdates · setWebhook · deleteWebhook · getWebhookInfoRecibir actualizaciones (arriba)
setVoiceCallSettings · getVoiceCallSettings · endVoiceCall · sendVoiceCallContext · getVoiceCallUsage · startVoiceCall · answerVoiceCallToolQuery · setVoiceCallApiKey · setVoiceCallMcpServer …Bots de voz (abajo, en Llamadas de voz)
Qué se puede poner en chat_id

En un chat uno a uno, el ID de la persona (positivo); en un grupo básico, el ID del grupo (negativo); o bien el nombre de usuario de la persona ("@hana_lee"). Todos se pueden obtener del chat.id de las actualizaciones. Los IDs de canales y supergrupos (-100…) todavía no existen (400 chat not found).

getMe

GET/bot<token>/getMe

Sirve para comprobar que el token es correcto. Sin parámetros.

Devuelve: User. En el caso de un bot se añaden can_join_groups (true), can_read_all_group_messages (true), supports_inline_queries (false), can_connect_to_business (false) y has_main_web_app (false).

sendMessage

POST/bot<token>/sendMessage

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino (ver el recuadro de arriba)
textStringSíDe 1 a 4.096 caracteres. Se envía tal cual
reply_markupInlineKeyboardMarkup · ReplyKeyboardMarkup · ReplyKeyboardRemove · ForceReplyOpcionalBotones
disable_notificationBooleanOpcionalEnviar sin sonido
parse_mode, entities, reply_parameters, link_preview_options …Se ignoraSe aceptan pero no se usan. No se aplica ningún formato

Devuelve: el Message enviado

Para escribir a una persona, esa persona tiene que haber escrito antes al bot (403 Forbidden: bot can't initiate conversation with a user). Para escribir en un grupo, el bot tiene que ser miembro de ese grupo.

sendPhoto

POST/bot<token>/sendPhoto

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino
photoInputFile o StringSíUn archivo subido como multipart/form-data (hasta 10 MB; JPEG, PNG o GIF) o el file_id de una foto recibida antes. Las URL todavía no se admiten
captionStringOpcionalDe 0 a 1.024 caracteres
reply_markupIgual que en sendMessageOpcional
disable_notificationBooleanOpcional

Devuelve: el Message enviado (con un file_id nuevo en photo)

sendDocument

POST/bot<token>/sendDocument

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino
documentInputFile o StringSíUn archivo subido como multipart/form-data (sin restricción de formato, hasta 20 MB) o el file_id de un archivo recibido antes. Las URL todavía no se admiten
filenameStringOpcionalNombre que verá quien lo reciba. Si no se indica, se usa el del archivo subido
captionStringOpcionalDe 0 a 1.024 caracteres
reply_markupIgual que en sendMessageOpcional
disable_notificationBooleanOpcional
thumbnail, disable_content_type_detectionSe ignoranSe aceptan, pero no se usan

Devuelve: el Message enviado (con un file_id nuevo en document)

El formato (mime_type) se deduce de la extensión del nombre del archivo. Los archivos enviados desde la aplicación pueden llegar a 2 GB, pero lo que el bot sube y descarga por HTTP tiene un límite de 20 MB, igual que en Telegram.

sendLocation

POST/bot<token>/sendLocation

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino
latitude, longitudeFloatSíLatitud (de −90 a 90) y longitud (de −180 a 180). Fuera de rango: 400 Bad Request: GEO_POINT_INVALID
horizontal_accuracyFloatOpcionalRadio de incertidumbre en metros, de 0 a 1.500. Se redondea a un entero al guardarse
live_periodIntegerOpcionalLa convierte en una ubicación en tiempo real: de 60 a 86.400 segundos, o 2147483647 (0x7FFFFFFF) hasta que se detenga. Cualquier otro valor da 400 Bad Request: wrong live_period
headingIntegerOpcionalDirección de desplazamiento de una ubicación en tiempo real, de 1 a 360 grados
proximity_alert_radiusIntegerOpcionalRadio de la alerta de proximidad de una ubicación en tiempo real, en metros. Se guarda y se muestra, pero todavía no se envía ninguna alerta
reply_markupIgual que en sendMessageOpcional
disable_notificationBooleanOpcional

Devuelve: el Message enviado (con una Location en location)

sendVenue

POST/bot<token>/sendVenue

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino
latitude, longitudeFloatSíDónde está el lugar (igual que en sendLocation)
titleStringSíNombre del lugar
addressStringSíDirección
foursquare_id, foursquare_typeStringOpcionalID y tipo del lugar en Foursquare; se transmiten tal cual
google_place_id, google_place_typeStringOpcionalID y tipo del lugar en Google. Solo se usan si no hay foursquare_id
reply_markupIgual que en sendMessageOpcional
disable_notificationBooleanOpcional

Devuelve: el Message enviado (con un Venue en venue y el mismo punto en location)

Sin title o address obtienes 400 Bad Request: title and address are required.

sendContact

POST/bot<token>/sendContact

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat de destino
phone_numberStringSíNúmero de teléfono; se transmite tal como está escrito
first_nameStringSíNombre
last_nameStringOpcionalApellido
vcardStringOpcionalDatos adicionales en formato vCard, hasta 64 KB
reply_markupIgual que en sendMessageOpcional
disable_notificationBooleanOpcional

Devuelve: el Message enviado (con un Contact en contact)

Una tarjeta de contacto enviada por un bot nunca lleva user_id, aunque el número pertenezca a una cuenta de Pabal: un bot no tiene contactos, y si se rellenara, el bot podría averiguar de quién es un número enviando una tarjeta por número. Sin phone_number o first_name obtienes 400 Bad Request: phone_number and first_name are required.

editMessageLiveLocation

POST/bot<token>/editMessageLiveLocation

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat en el que está el mensaje
message_idIntegerSíLa ubicación en tiempo real que se mueve (una enviada por el bot)
latitude, longitudeFloatSíLa nueva posición
horizontal_accuracyFloatOpcionalRadio de incertidumbre en metros, de 0 a 1.500
headingIntegerOpcionalDirección de desplazamiento, de 1 a 360 grados
proximity_alert_radiusIntegerOpcionalRadio de la alerta de proximidad en metros. Con 0 se desactiva
live_periodIntegerOpcionalNuevo periodo para compartir, en segundos contados desde que se envió el mensaje. No se puede ampliar más de un día sobre el actual; 2147483647 significa hasta que se detenga
reply_markupInlineKeyboardMarkupOpcionalBotones nuevos
inline_message_idStringNo admitidoNo hay modo inline, así que 400

Devuelve: el Message editado

Una ubicación en tiempo real que ya terminó —detenida o con el periodo agotado— no se puede mover ni revivir ampliando su periodo (400 Bad Request: message can't be edited). Lo mismo vale para un mensaje que no es una ubicación en tiempo real.

Un movimiento hecho menos de 10 segundos después del último que se aplicó, o de menos de 10 m, se deja pasar sin guardarlo. Detenerla y cambiar el periodo o el radio de alerta siempre se aplican. Cuando se deja pasar un movimiento, el Message devuelto muestra la última posición aplicada, así que no pasa nada por enviar uno cada pocos segundos.

stopMessageLiveLocation

POST/bot<token>/stopMessageLiveLocation

Parámetros: chat_id, message_id y reply_markup (opcional). Detiene la ubicación en tiempo real donde estaba por última vez. Su periodo se reduce al tiempo que de verdad pasó, así que todas las aplicaciones la muestran como terminada. Si ya estaba detenida o terminada, 400 Bad Request: message is not modified: …. Devuelve: el Message editado.

editMessageText

POST/bot<token>/editMessageText

ParámetroTipoObligatorioDescripción
chat_idInteger o StringSíChat en el que está el mensaje
message_idIntegerSíMensaje que se edita (uno enviado por el bot)
textStringSíTexto nuevo, de 1 a 4.096 caracteres
reply_markupInlineKeyboardMarkupOpcionalBotones nuevos. Si lo omites, los botones desaparecen (igual que en Telegram)
inline_message_idStringNo admitidoNo hay modo inline, así que 400

Devuelve: el Message editado. El cambio se refleja al instante en la aplicación, y los mensajes que edita una persona le llegan al bot como edited_message.

Si el texto y los botones son idénticos a los anteriores, 400 Bad Request: message is not modified: …; si intentas editar un mensaje ajeno, 400 Bad Request: message can't be edited.

editMessageCaption

POST/bot<token>/editMessageCaption

Parámetros: chat_id, message_id, caption (de 0 a 1.024 caracteres; si lo omites, se borra el pie) y reply_markup. Devuelve: el Message editado.

editMessageReplyMarkup

POST/bot<token>/editMessageReplyMarkup

Deja el texto como está y cambia solo los botones. Parámetros: chat_id, message_id y reply_markup (si lo omites, se borran los botones). Devuelve: el Message editado.

deleteMessage

POST/bot<token>/deleteMessage

Parámetros: chat_id y message_id. Borra el mensaje para ambas partes del chat. Si el mensaje no existe, 400 Bad Request: message to delete not found. Devuelve: True.

answerCallbackQuery

POST/bot<token>/answerCallbackQuery

Responde a un botón pulsado por una persona (CallbackQuery). Solo se puede responder en menos de 10 segundos y una sola vez.

ParámetroTipoObligatorioDescripción
callback_query_idStringSíEl callback_query.id de la actualización
textStringOpcionalTexto que aparece un momento sobre la pantalla
show_alertBooleanOpcionalCon true, se muestra en un cuadro con botón de confirmación
urlStringOpcionalDirección que abrirá la aplicación
cache_timeIntegerOpcionalSegundos que la aplicación recordará esta respuesta

Devuelve: True. Si es demasiado tarde o ya se respondió, 400 Bad Request: query is too old and response timeout expired or query ID is invalid.

sendChatAction

POST/bot<token>/sendChatAction

Se acepta por compatibilidad y devuelve True, pero por ahora la aplicación no muestra «escribiendo…».

getChat

GET/bot<token>/getChat?chat_id=…

Parámetro: chat_id (numérico). Si es una persona, esa persona; si es un grupo, solo los grupos de los que el bot es miembro. Devuelve: Chat. Si no existe o no se puede ver, 400 Bad Request: chat not found.

getFile

GET/bot<token>/getFile?file_id=…

Obtiene la ruta de descarga de una foto recibida a partir de su file_id. Devuelve: File. Después se descarga desde esta dirección.

https://pabal.me/file/bot<token>/<file_path>

El file_id es también el derecho a obtener esa foto. Si el valor no es válido, 400 Bad Request: wrong file identifier/HTTP URL specified.

setMyCommands

POST/bot<token>/setMyCommands

ParámetroTipoObligatorioDescripción
commandsArray of BotCommandSí100 como máximo
language_codeStringOpcionalSe guarda como lista de ese idioma. Por ahora la aplicación solo muestra la lista predeterminada, sin código de idioma
scopeBotCommandScopeSe ignora

Devuelve: True. Si el menú no cumple las reglas, no se guarda nada: 400 Bad Request: BOT_COMMAND_INVALID (un comando), BOT_COMMAND_DESCRIPTION_INVALID (una descripción vacía o de más de 256 caracteres), BOT_COMMANDS_TOO_MUCH (más de 100).

getMyCommands

GET/bot<token>/getMyCommands

Parámetro: language_code (opcional). Devuelve: Array of BotCommand.

deleteMyCommands

POST/bot<token>/deleteMyCommands

Parámetro: language_code (opcional). Vacía esa lista. Devuelve: True.

logOut · close

En Telegram son métodos que se usan al pasar a un servidor local de la Bot API. En Pabal no hay adónde pasar, así que solo se aceptan y devuelven True. Para invalidar un token, usa /revoke de BotFather.

Objetos

opcional junto a un campo significa que puede no aparecer. Pabal no envía los demás campos de Telegram que no figuran aquí.

Update

Una actualización. Contiene update_id y uno de los campos siguientes.

CampoTipoDescripción
update_idIntegerNúmero que aumenta de 1 en 1. Se usa en el offset de getUpdates
message opcionalMessageMensaje nuevo para el bot (en un chat uno a uno, o todos los mensajes de los grupos de los que el bot es miembro)
edited_message opcionalMessageMensaje editado
callback_query opcionalCallbackQueryPulsación de un botón inline
voice_call opcionalVoiceCallInicio y fin de una llamada a un bot de voz o de una llamada que hizo (solo llega si se pide por su nombre)
voice_call_tool_query opcionalVoiceCallToolQueryHerramienta del bot a la que llamó el modelo durante la llamada (solo llega si se pide por su nombre)
voice_call_transcript opcionalVoiceCallTranscriptUn turno de la transcripción durante la llamada (solo llega si se pide por su nombre)

User

CampoTipoDescripción
idIntegerID de usuario (solo tiene sentido dentro de este servidor)
is_botBooleantrue si es un bot
first_nameStringNombre. En una cuenta eliminada, Deleted Account
last_name opcionalStringApellido
username opcionalStringNombre de usuario (sin @)

Chat

CampoTipoDescripción
idIntegerSi es una persona, su ID (positivo); si es un grupo básico, un número negativo
typeStringprivate o group
title opcionalStringNombre del grupo (group)
first_name, last_name, username opcionalStringNombre y nombre de usuario de la otra persona (private)

Message

CampoTipoDescripción
message_idIntegerNúmero del mensaje dentro de este chat
from opcionalUserRemitente
chatChatChat en el que está el mensaje
dateIntegerHora de envío (segundos Unix)
edit_date opcionalIntegerHora de la última edición
text opcionalStringTexto (siempre presente si no es un mensaje con foto, archivo, ubicación, lugar o contacto)
entities opcionalArray of MessageEntityComandos, menciones, URL y hashtags del texto
photo opcionalArray of PhotoSizeFoto (en Pabal, un único elemento con el original)
document opcionalDocumentArchivo
location opcionalLocationUna ubicación o una ubicación en tiempo real. Los mensajes de lugar también traen aquí su ubicación
venue opcionalVenueUn lugar
contact opcionalContactUna tarjeta de contacto
caption opcionalStringPie de foto
caption_entities opcionalArray of MessageEntityComandos, menciones, URL y hashtags del pie de foto
reply_markup opcionalInlineKeyboardMarkupBotones inline que lleva el mensaje

MessageEntity

CampoTipoDescripción
typeStringbot_command, mention, url, hashtag
offsetIntegerPosición inicial (en unidades de código UTF-16)
lengthIntegerLongitud (en unidades de código UTF-16)

El servidor las detecta en el texto y las añade automáticamente. Todavía no hay entidades de formato como negrita o cursiva.

PhotoSize

CampoTipoDescripción
file_idStringID para descargar (getFile) y para volver a enviar (sendPhoto)
file_unique_idStringEl mismo valor para la misma foto, aunque sea otro bot. No sirve para descargar
width, heightIntegerTamaño en píxeles
file_sizeIntegerBytes

Document

CampoTipoDescripción
file_idStringID para descargar (getFile) y para volver a enviar (sendDocument)
file_unique_idStringEl mismo valor para el mismo archivo, aunque sea otro bot. No sirve para descargar
file_nameStringNombre que le puso quien lo envió
mime_typeStringFormato que indicó quien lo envió
file_sizeIntegerBytes

Location

CampoTipoDescripción
latitude, longitudeFloatLatitud y longitud
horizontal_accuracy opcionalFloatRadio de incertidumbre en metros
live_period opcionalIntegerPeriodo para compartir una ubicación en tiempo real, en segundos contados desde que se envió el mensaje. Al detenerla, se reduce al tiempo que de verdad pasó
heading opcionalIntegerDirección de desplazamiento, de 1 a 360 grados
proximity_alert_radius opcionalIntegerRadio de la alerta de proximidad en metros

Una ubicación en tiempo real que comparte una persona vuelve a llegar como edited_message cada vez que el servidor aplica un movimiento.

Venue

CampoTipoDescripción
locationLocationDónde está el lugar
titleStringNombre del lugar
addressStringDirección
foursquare_id, foursquare_type opcionalStringID y tipo del lugar en Foursquare
google_place_id, google_place_type opcionalStringID y tipo del lugar en Google

Contact

CampoTipoDescripción
phone_numberStringEl número tal como lo escribió quien lo envió
first_nameStringNombre
last_name opcionalStringApellido
user_id opcionalIntegerLa cuenta de Pabal con ese número. Solo aparece si quien envía tiene a esa persona guardada en sus contactos, o si es esa misma persona
vcard opcionalStringDatos adicionales en formato vCard

File

CampoTipoDescripción
file_id, file_unique_idStringIgual que en PhotoSize
file_sizeIntegerBytes
file_pathStringCon la forma photos/<file_id>.jpg o documents/<file_id>. Se añade detrás de /file/bot<token>/ para descargar

CallbackQuery

CampoTipoDescripción
idStringID que se pasa a answerCallbackQuery
fromUserPersona que pulsó el botón
message opcionalMessageMensaje que lleva el botón
chat_instanceStringValor que identifica ese chat
data opcionalStringEl callback_data del botón

InlineKeyboardMarkup

inline_keyboard: Array of Array of InlineKeyboardButton. El array exterior son las filas y cada array interior, los botones de una fila. Como máximo 100 filas y 100 botones por mensaje.

InlineKeyboardButton

CampoTipoDescripción
textStringTexto del botón
callback_data uno de los dosStringValor que se envía al bot al pulsar, de 1 a 64 bytes
url uno de los dosStringDirección que se abre al pulsar

Otros tipos como switch_inline_query, web_app, login_url o pay todavía no existen (400).

ReplyKeyboardMarkup

CampoTipoDescripción
keyboardArray of Array of KeyboardButtonPanel de botones bajo el campo de texto
resize_keyboard, one_time_keyboard, is_persistent, selective opcionalBooleanAjustar el tamaño · ocultar tras un uso · mostrar siempre · solo para ciertas personas
input_field_placeholder opcionalStringTexto de ayuda en el campo de texto

KeyboardButton

Una cadena, o un objeto con text y los campos opcionales request_contact (enviar mi contacto) y request_location (enviar mi ubicación), de tipo Boolean.

ReplyKeyboardRemove

{"remove_keyboard": true}: oculta el panel de botones. selective es opcional.

ForceReply

{"force_reply": true}: la aplicación abre el campo de texto en modo de respuesta a este mensaje. selective e input_field_placeholder son opcionales.

BotCommand

CampoTipoDescripción
commandStringDe 1 a 32 caracteres: letras latinas minúsculas, números y guion bajo (sin /)
descriptionStringDe 1 a 256 caracteres

WebhookInfo

CampoTipoDescripción
urlStringDirección del webhook; si no hay, una cadena vacía
has_custom_certificateBooleanSiempre false
pending_update_countIntegerNúmero de actualizaciones que esperan a ser entregadas
ip_address opcionalStringÚltima IP a la que se envió
last_error_date opcionalIntegerHora del último fallo (segundos Unix)
last_error_message opcionalStringMotivo del último fallo (lista)
max_connections opcionalIntegerEl valor que pasaste a setWebhook
allowed_updates opcionalArray of StringEl valor que pasaste a setWebhook

Llamadas de voz

Estos métodos solo existen en Pabal. Un bot de voz es un bot al que se llama desde la aplicación y cuyas llamadas atiende un modelo de voz de IA; con estos métodos se configura ese modelo y se gestionan las llamadas. Lo que tiene que estar activado, cómo activarlo y los ejemplos están en la guía Bots de voz. Los métodos existen también en un servidor con la voz desactivada, así que se pueden leer los ajustes, pero un bot con la voz desactivada o que el operador aún no ha autorizado no puede cambiar sus ajustes salvo para desactivar o borrar (403 VOICE_NOT_AVAILABLE).

setVoiceCallSettings

POST/bot<token>/setVoiceCallSettings

Cambia los ajustes de voz del bot. Solo cambia lo que envías; el servidor lo revisa todo y lo escribe de una vez, o lo rechaza entero. 30 veces por hora por bot (sumando @BotFather).

ParámetroTipoObligatorioDescripción
enabledBooleanOpcionalActivar solo es posible después de aceptar las reglas de los bots de voz en @BotFather (403 VOICE_RULES_NOT_ACCEPTED). Desactivar siempre funciona
instructionsStringOpcionalInstrucciones del modelo, hasta 8.192 bytes. "" las borra (no en un bot gestionado activado)
greetingStringOpcionalPrimer saludo, hasta 512 bytes. Con "", lo hace el modelo por su cuenta
voiceStringOpcionalID de voz, kore por defecto (lista)
languageStringOpcionalko-KR (por defecto) · en-US · ja-JP · cmn-CN · fr-FR · es-US · id-ID · vi-VN · ar-EG (lista). No distingue mayúsculas y minúsculas, y zh-CN se guarda como cmn-CN. Un bot que no está en coreano ni en inglés solo recibe llamadas después de que el operador lea las instrucciones y el saludo y lo autorice
max_call_durationIntegerOpcionalSegundos, de 60 a limits.max_call_duration
max_concurrent_callsIntegerOpcionalDe 1 a limits.max_concurrent_calls
toolsArray of VoiceCallToolOpcionalHerramientas del bot a las que el modelo puede llamar durante la llamada: {"name", "description", "parameters"?, "timeout_ms"?}. Reglas en Definir herramientas. En un formulario, como cadena JSON
transcriptBooleanOpcionalInterruptor de la transcripción. Para activarlo hacen falta las condiciones para propietarios de bots
modeStringOpcionalmanaged (el modelo de IA de Pabal) o stream (modo stream)
stream_url, stream_secretStringOpcionalJunto con mode=stream. El secreto, solo en el cuerpo de la petición

Devuelve: True

getVoiceCallSettings

GET/bot<token>/getVoiceCallSettings

Sin parámetros. Los ajustes actuales; si el bot puede recibir llamadas ahora (available, unavailable_reason); los límites del servidor; la lista de voces e idiomas; adónde irían las consultas de herramienta y la transcripción; y el estado de la clave propia, el modo stream y los servidores MCP. Las claves y los secretos nunca aparecen, solo sus huellas. Los campos están en Bots de voz — Ver los ajustes actuales.

Devuelve: VoiceCallSettings (objeto)

endVoiceCall

POST/bot<token>/endVoiceCall

ParámetroTipoObligatorioDescripción
voice_call_idStringSívoice_call.id
farewellBooleanOpcionaltrue por defecto: el modelo se despide brevemente y cuelga (si no ha colgado en 10 segundos, el servidor la termina). false: cuelga de inmediato

Devuelve: True. Si no es una llamada en curso de este bot: 400 VOICE_CALL_NOT_FOUND.

sendVoiceCallContext

POST/bot<token>/sendVoiceCallContext

ParámetroTipoObligatorioDescripción
voice_call_idStringSíUna llamada establecida
textStringSíNota del propietario del bot para el modelo. Hasta 2.000 caracteres y 6.144 bytes, revisada con las reglas de contenido
respondBooleanOpcionalfalse por defecto. true: el modelo reacciona enseguida

Devuelve: True. Antes de la conexión: VOICE_CALL_NOT_ACTIVE; llamada en modo stream: VOICE_CONTEXT_NOT_SUPPORTED; demasiado larga: VOICE_CONTEXT_TOO_LONG; más de 10 por minuto en una llamada: 429.

getVoiceCallUsage

GET/bot<token>/getVoiceCallUsage

ParámetroTipoObligatorioDescripción
periodStringOpcionaltoday (por defecto) o month
monthStringOpcionalYYYY-MM, solo junto con period=month

Devuelve: period, from_date, to_date, calls, seconds, missed, refused (busy·budget·unavailable), platform_seconds, own_key_seconds, remaining_seconds_today (bot·owner) y, en un bot que alguna vez activó las llamadas, outbound (today·limits); los días se cuentan según la zona horaria del servidor

startVoiceCall

POST/bot<token>/startVoiceCall

El bot llama a una persona. Solo puede hacerlo un bot cuyo propietario lo activó en @BotFather y que el operador revisó, y solo a quienes permitieron que ese bot les llame. Las respuestas y cómo se evalúan las peticiones están en Bots de voz — Llamar.

ParámetroTipoObligatorioDescripción
user_idIntegerSíLa persona a la que llamar
purposeStringSíEl que eligió el bot entre reminder, wake_up, delivery, appointment
contextStringSíLo que solo el modelo sabe, hasta 1.000 caracteres y 3.072 bytes, comprobado con las reglas de contenido
max_durationIntegeropcionalLo más que puede durar una vez contestada, en segundos, de 30 a 300 (hasta el máximo del bot). 180 por defecto
ring_timeoutIntegeropcionalSegundos que suena, de 30 a 45. 40 por defecto

Devuelve: {"voice_call_id": "…"}; solo significa que se recibió la petición: si sonó y si contestaron llega en actualizaciones voice_call. Rechazos: 403 VOICE_OUTBOUND_OFF: <motivo>, 403 USER_UNAVAILABLE (siempre el mismo cuerpo), 429, 503 VOICE_UNAVAILABLE. No se puede llamar desde la respuesta de un webhook.

answerVoiceCallToolQuery

POST/bot<token>/answerVoiceCallToolQuery

ParámetroTipoObligatorioDescripción
tool_query_idStringSíEl id de la VoiceCallToolQuery
resultString · Object · ArrayUno de los dosResultado de la herramienta, hasta 16.384 bytes
errorStringUno de los dosMensaje de fallo del bot, hasta 512 bytes

Devuelve: True. La primera respuesta es la última. Si llega tarde: 400 TOOL_QUERY_EXPIRED: answered|timeout|cancelled|call_ended|unreachable; ID desconocido: TOOL_QUERY_ID_INVALID; respuesta rechazada: TOOL_RESULT_EMPTY·TOOL_RESULT_INVALID·TOOL_RESULT_TOO_LONG·TOOL_ERROR_TOO_LONG·TOOL_RESULT_REFUSED: <código>. Al POST de una consulta de herramienta recibido por webhook también se puede responder en el cuerpo de la respuesta.

setVoiceCallApiKey · deleteVoiceCallApiKey

POST/bot<token>/setVoiceCallApiKey

ParámetroTipoObligatorioDescripción
providerStringSígoogle (clave JSON de cuenta de servicio de Vertex AI) o openai (sk-…)
api_keyStringSíLa clave. Solo en el cuerpo de la petición (en la cadena de consulta: 400), hasta 8 KiB

Devuelve: True; la clave solo se guarda tras pasar una sesión de prueba de la pasarela. API_KEY_INVALID, API_KEY_NO_REALTIME_ACCESS, 503 API_KEY_CHECK_UNAVAILABLE (no se guarda), 403 VOICE_OWN_KEY_NOT_AVAILABLE (este servidor no acepta claves propias). deleteVoiceCallApiKey no lleva parámetros y siempre devuelve True. Ninguno de los dos métodos se puede llamar con bots.sendCustomRequest, y setVoiceCallApiKey tampoco en una respuesta de webhook. Más detalles en Clave de modelo propia.

Métodos de los servidores MCP

MétodoParámetrosDevuelve
setVoiceCallMcpServerlabel, url, auth (objeto) y, opcionalmente, audience, allowed_tools, requested_level, timeout_ms, tools (clasificación aportada por el propietario), declaration, auto_repinResultado del registro (status, job_id). Si cambia el destinatario: 400 MCP_CHANGE_NEEDS_CONFIRMATION y después confirmación en @BotFather
refreshVoiceCallMcpServerlabelVuelve a revisarlo (refreshing: true, job_id)
deleteVoiceCallMcpServerlabelTrue; funciona aunque MCP esté desactivado
getVoiceCallMcpBindingNingunoiss, sub (bot:<id>), issuer_document, jwks_uri, audiences
createVoiceCallMcpClientKeylabelLa jwk pública y su thumbprint (la clave privada nunca sale de Pabal)

auth y los secretos se envían solo en el cuerpo de la petición. En un servidor sin MCP: 403 VOICE_NOT_AVAILABLE: MCP tools are not available on this server. Más detalles en Bots de voz — Servidores MCP.

Para recibir actualizaciones de voz

voice_call, voice_call_tool_query y voice_call_transcript solo llegan si las pides por su nombre: ponlas en el allowed_updates de getUpdates o de setWebhook. Con una lista vacía no llegan, y lo que ocurrió antes de pedirlas no se acumula. Una consulta de herramienta llega por un POST aparte si hay webhook, o al principio del siguiente getUpdates si se llamó a getUpdates en los últimos 15 segundos.

VoiceCall

CampoTipoDescripción
idStringID de la llamada (decimal sin signo)
directionStringincoming (una llamada al bot) u outgoing (una llamada que hizo el bot). Siempre está
eventStringstarted, ended, missed, refused; en una llamada que hizo el bot, started, ended, not_answered, failed
from opcionalUserSolo en llamadas al bot. Quien llama: id, is_bot, first_name, last_name, language_code. Sin nombre de usuario ni número de teléfono
to opcionalObjectSolo en llamadas que hizo el bot: {"id": …}, solo el id de quien recibe la llamada
purpose opcionalStringSolo en llamadas que hizo el bot: el propósito de la petición
dateIntegerMomento en que ocurrió (segundos Unix). started: en una llamada desde las aplicaciones, cuando termina el intercambio de claves; en una llamada desde el Apple Watch, cuando se conecta el audio del reloj. ended llega hasta 10 segundos más tarde en un servidor que espera la transcripción o que tiene «Guardar conversación» activado. En una llamada que hizo el bot, el ended de una llamada contestada siempre llega hasta 10 segundos más tarde, sea cual sea la configuración del servidor, mientras se espera el uso de la pasarela
max_duration opcionalIntegerDuración máxima de esta llamada (segundos): started, ended
start_date, duration opcionalIntegerMomento en que se estableció y segundos que estuvo establecida (reloj del servidor): ended
end_reason opcionalStringcaller (callee en una llamada que hizo el bot), bot, max_length, failed, operator, suspended: ended, missed
refused_reason opcionalStringbusy, budget, unavailable: refused
transcript opcionalObject{"turns": [{"role", "text", "offset_ms"}], "truncated"}: ended, cuando la transcripción estaba activada. Nunca en una llamada que hizo el bot

VoiceCall no tiene ningún campo que indique si quien llama eligió «Guardar conversación». Es intencionado: ese texto pertenece a quien llama y no va al bot. Por eso, en un servidor con «Guardar conversación» activado, el ended de todas las llamadas que no son de modo stream espera lo mismo, y el número del mensaje siguiente al registro de la llamada es, en todas las llamadas, al menos 31 mayor que el del registro (los números se reservan de antemano).

VoiceCallToolQuery

CampoTipoDescripción
idStringID que se pasa a answerVoiceCallToolQuery
voice_call_idStringID de la llamada
fromUserQuien llama (mismos campos que en VoiceCall)
nameStringNombre de la herramienta
argumentsStringArgumentos: el texto de un objeto JSON (revisado por el servidor)
budget_msIntegerMilisegundos desde que se recibe hasta que la respuesta tiene que llegar al servidor

VoiceCallTranscript

CampoTipoDescripción
voice_call_idStringID de la llamada
seqIntegerNúmero de turno
roleStringcaller o bot
textStringTexto escrito por la IA. Si contiene un número de tarjeta o de identificación nacional, los dígitos pasan a *
is_finalBooleanSiempre true
offset_ms, dateIntegerMilisegundos desde que empezó el audio de la llamada, y la hora

Solo llega por la Bot API HTTP. La llamada completa está en el campo transcript del voice_call de fin de llamada.

Modo stream (mode=stream)

En modo stream, el audio de la llamada va al servidor del propietario del bot en lugar del modelo de IA de Pabal. Si envías a setVoiceCallSettings mode=stream, stream_url=wss://… y stream_secret=… (de 32 a 128 caracteres ASCII imprimibles, solo en el cuerpo de la petición), la pasarela de Pabal intenta conectarse una vez a esa dirección (sondeo) y, si lo consigue, se activa. Hacen falta las condiciones para propietarios de bots y una compilación de la aplicación con la pantalla de confirmación del modo stream. Configuración, resultados del sondeo y ejemplos: Bots de voz — Modo stream.

  • Conexión: TLS 1.2 o superior, certificado público que coincida con el nombre de la URL, subprotocolo pabal.voice.v1, sin compresión, hasta 64 KiB por mensaje y 4 KiB por texto, sin redirecciones.
  • Firma: 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 es el host de la URL que diste. Comprueba los 300 segundos, el nonce de un solo uso, la comparación byte a byte y que start.call_id sea igual a call (más detalles).
  • Audio: los mensajes de texto son eventos JSON, y los binarios, PCM16 little-endian, mono, 24 kHz. La voz de quien llama llega en trozos de 20 ms (960 bytes).
  • Pabal → bot: start (una vez) · live (terminó el aviso de IA) · audio · mark · cleared · buffer_full · stop (→ cierre 1000).
  • Bot → Pabal: ready (en los 3 segundos siguientes a start, lo primero de todo) · audio (después de live) · clear · mark · hangup.

La forma de cada mensaje está en la tabla de Bots de voz — Especificación.

Errores de los métodos de voz

Los códigos de error de los métodos de voz y su significado están reunidos en Bots de voz — Errores. Un 403 tiene la forma Forbidden: <código>: <descripción> (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 siempre es exactamente Forbidden: USER_UNAVAILABLE, sin descripción, y si se supera el límite por hora llega 429 con retry_after.

Diferencias con la Bot API de Telegram

  • Tipos de actualización: solo llegan message, edited_message, callback_query y los tipos de bots de voz propios de Pabal (voice_call, voice_call_tool_query, voice_call_transcript). No hay publicaciones de canal, consultas inline, pagos, encuestas, cambios de miembros (my_chat_member), etc.
  • Formato: parse_mode y entities se ignoran y el texto se envía tal cual. Solo los comandos, las menciones, las URL y los hashtags se marcan automáticamente.
  • Tipos de chat: solo chats uno a uno y grupos básicos. No hay canales, supergrupos ni temas de foro.
  • Multimedia: solo fotos, archivos (sendDocument), ubicaciones, ubicaciones en tiempo real, lugares y contactos. No hay mensajes que se reproduzcan como vídeo o como voz, ni stickers, álbumes (sendMediaGroup), encuestas o envío mediante URL. Lo que se sube y se descarga por HTTP tiene un límite de 20 MB.
  • Ubicaciones: la alerta de proximidad de una ubicación en tiempo real (proximity_alert_radius) solo se guarda, nunca se envía. Los movimientos a menos de 10 segundos o de 10 m del último aplicado se dejan pasar, y una tarjeta de contacto enviada por un bot no lleva user_id.
  • Bots en grupos: no hay modo de privacidad, así que reciben todos los mensajes del grupo.
  • Cola: las actualizaciones no recogidas se guardan en memoria, hasta las 1.000 más recientes por bot, y se pierden al reiniciar el servidor (Telegram las conserva 24 horas).
  • Webhooks: las actualizaciones se envían de una en una y en orden (max_connections solo se guarda), no se aceptan certificados autofirmados y no hay restricción de puerto.
  • IDs: los IDs de usuario, de mensaje y de archivo solo tienen sentido dentro de este servidor. Como no hay canales ni supergrupos, tampoco hay IDs con la forma -100….
  • Métodos inexistentes: los que no están en la lista de arriba (forwardMessage, copyMessage, sendVideo, sendPoll, getChatMember, banChatMember, answerInlineQuery …) devuelven 404 Not Found: method not found.