Docs para desarrolladores
Español

API de Pabal

API de Pabal (MTProto)

Para crear un cliente que se conecte al servidor igual que la aplicación: datos de conexión, clave pública del servidor, flujo de inicio de sesión, actualizaciones y alcance del soporte.

La aplicación Pabal se comunica con el servidor mediante MTProto 2.0. Consulta este documento si vas a crear un programa que se conecte de la misma manera: otra aplicación, una automatización que funcione con una cuenta de usuario o un cliente para investigación. Si lo que vas a crear es un bot, te basta con la Bot API, que es más sencilla.

Consulta también la documentación de Telegram

Pabal sigue el protocolo público de Telegram, así que la referencia para las definiciones detalladas del protocolo y de los métodos son los documentos de MTProto y de los métodos de la API. Este documento recoge lo que cambia al conectarse a un servidor Pabal y el alcance del soporte.

Datos de conexión

ConceptoValor
Dirección122.34.175.215
Puerto8443 (TCP)
DCDel 1 al 5, todos con la misma dirección. Puedes conectarte a cualquier DC; lo habitual es usar el 2
ProtocoloMTProto 2.0, capa (layer) de la API 216
TransportesAbridged, Intermediate, Padded Intermediate y Full, cada uno también con ofuscación (obfuscated2)
Clave pública del servidorserver-key.pem · fingerprint 8724853375441383205
api_id · api_hashNo se comprueban. Pon cualquier valor

Todavía no hay transporte HTTP, transporte WebSocket ni MTProxy. El reloj del dispositivo cliente debe estar en hora: los números de los mensajes MTProto se derivan de la hora, así que si el reloj va muy desviado, el servidor descarta los mensajes.

Clave pública del servidor

La primera vez que se conecta, un cliente MTProto cifra el intercambio de la clave de autorización con la clave pública RSA del servidor. Los clientes de Telegram llevan incorporada la clave pública de Telegram, así que para conectarse a Pabal hay que incorporar esta clave en su lugar (o además). Esta clave impide que otro servidor se haga pasar por el servidor Pabal.

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA4hH74xPQsUwr/pyXPdF4tVicYr6QbfeDrKC7mUOVrPLSL4FtmgGn
w+O4u6lVvOf3Udd1KY6+OL4fUZdMBlLzwsoGLoniiVR09dnvyXHE8LhQSS+i1LmI
oJbhQwXplLnUJf272fLXkD23e7ppKLkjYk+jeYObueCy5HYMSThklVeXEzbZVGZv
47o/mjU2vyFoRpa6wCIE4rpj1UIPtOMpekMI/TocIlGVJ+ch6cAVNxIDro53a1eG
/1oZRLQH4oViEGxeMMjBMY5gk5HPkZvjbqy4h8TjXEz7O5o0BRsSqG/OPtP/dRQV
X4ewPhj2WCU4e6l5X59ZKIcv4sQLOwClqQIDAQAB
-----END RSA PUBLIC KEY-----
curl -s -o server-key.pem https://pabal.me/docs/server-key.pem

Esta clave se genera una sola vez, la primera vez que arranca el servidor, y no cambia. Comprueba que el valor de Loaded RSA key … (fingerprint …) en el log del servidor coincide con el fingerprint de arriba.

Conectarse con Telethon

Este es un ejemplo en el que, con Telethon para Python, se inicia sesión con una cuenta de usuario y se intercambian mensajes. Regístrate antes en la aplicación (ver más abajo).

# pabal_client.py — pip install telethon==1.42.0
# En la misma carpeta, server-key.pem (la clave pública del servidor descargada arriba)
import asyncio

from telethon import TelegramClient, events
from telethon.crypto import rsa

rsa.add_key(open("server-key.pem").read(), old=False)          # clave pública del servidor Pabal

client = TelegramClient("pabal", api_id=1, api_hash="0" * 32)  # la sesión se guarda en pabal.session
client.session.set_dc(2, "122.34.175.215", 8443)


@client.on(events.NewMessage(incoming=True))
async def show(event):
    sender = await event.get_sender()
    print(f"{sender.first_name}: {event.raw_text}")


async def main():
    await client.start(phone=lambda: input("Número de teléfono (+8210…): "))   # la primera vez, introduce el código
    me = await client.get_me()
    print(f"Sesión iniciada: {me.first_name} (id {me.id})")
    await client.send_message("BotFather", "/help")
    await client.run_until_disconnected()


asyncio.run(main())
  • Usa Telethon 1.42, que es la versión que habla la capa 216. Las versiones más recientes intentan leer las respuestas con una capa superior y fallan con TypeNotFoundError.
  • Telethon tiene bloqueado el registro de cuentas nuevas (sign_up()). Regístrate en la aplicación o llama directamente a auth.signUp.
  • La sesión se guarda en el archivo pabal.session, así que las siguientes veces no se pide el código. Ese archivo es la llave de la cuenta: protégelo.

Flujo de inicio de sesión

1 · Clave de autorización (una vez) req_pq_multi → req_DH_params set_client_DH_params Auth key de 2048 bitsProtegida con la clave pública 2 · Inicio de sesión (una vez por clave) auth.sendCodeNúmero de teléfono sentCodeTypeSmsSMS o entrega por el admin SetUpEmailRequiredModo correo → pide dirección account.sendVerifyEmailCodepurpose: loginSetup auth.signInphone_code o código de email auth.authorizationSesión iniciada authorizationSignUpRequiredN.º nuevo → auth.signUp(nombre) Al recibir el código
Se crea la clave de autorización y se inicia sesión con un código

Explicación del diagrama

  • Dos fases: arriba, la fase en la que se crea la clave de autorización que se usará para cifrar (protocolo); abajo, la fase de inicio de sesión, que asocia una cuenta a esa clave (API). Las bibliotecas se encargan solas de la fase de arriba.
  • El inicio de sesión queda asociado a la clave de autorización: aunque abras varias sesiones con una clave con la que ya iniciaste sesión, todas quedan con la sesión iniciada. Si pierdes la clave (borrando el archivo de sesión), tendrás que volver a iniciar sesión.
  • El camino que sigue el código lo decide el operador del servidor: si es SMS o entrega por el administrador, llega sentCodeTypeSms; si es correo electrónico, llega sentCodeTypeSetUpEmailRequired, y el cliente pide la dirección de correo y llama a account.sendVerifyEmailCode (fila del medio).
  • La línea discontinua roja es el camino de un número nuevo: si el código es correcto pero la cuenta no existe, llega authorizationSignUpRequired, y al llamar a auth.signUp con un nombre termina el registro. El registro solo es posible después de acertar el código.
  • Los bots, en lugar de la fase de abajo, inician sesión con una sola llamada a auth.importBotAuthorization (con el token del bot).
ErrorCuándo
PHONE_NUMBER_INVALIDEl número es incorrecto, o es un número nuevo mientras el servidor tiene cerrados los registros
PHONE_NUMBER_BANNEDNúmero bloqueado por el operador, o el de una cuenta suspendida (si se eliminó mientras estaba suspendida, 1 año por defecto; el operador puede alargarlo o dejarlo indefinido)
FLOOD_WAIT_n (420)Se ha pedido el código con demasiada frecuencia. Vuelve a intentarlo dentro de n segundos
PHONE_CODE_INVALIDEl código es incorrecto (se bloquea al superar el número de intentos permitido)
PHONE_CODE_EXPIREDEl código ha caducado o está bloqueado, o el phone_code_hash es desconocido: vuelve a empezar desde sendCode
EMAIL_INVALID, EMAIL_NOT_ALLOWEDLa dirección de correo es incorrecta / la cuenta ya existe y ese no es su correo de inicio de sesión registrado
AUTH_KEY_UNREGISTERED (401)Se ha llamado, con una clave sin sesión iniciada, a un método que la requiere
Números de prueba

En un servidor en el que el operador ha activado los números de prueba, los números con la forma +99966XYYYY inician sesión sin que se entregue ningún código real, con el código XXXXX (la X repetida cinco veces). Es una función solo para servidores de desarrollo y está desactivada en los servidores de producción.

Recibir actualizaciones

  • En tiempo real: mientras la conexión está abierta, el servidor envía al instante los mensajes nuevos, las ediciones y los borrados como updateShortMessage y updates. La sesión que envió la petición recibe el resultado como respuesta RPC, así que no le llega lo mismo otra vez como push.
  • pts: los cambios de cada usuario llevan un número de orden (pts). Si el cliente ve un hueco en los pts recibidos, es que se ha perdido algo.
  • Ponerse al día: guarda el pts actual con updates.getState y, al volver a conectarte, obtén con updates.getDifference(pts, date, qts) los mensajes nuevos y los borrados de ese intervalo, junto con los usuarios y grupos relacionados. Si el pts que tiene el cliente va por delante del servidor (por ejemplo, si se reiniciaron los datos del servidor), llega differenceTooLong: vuelve a cargar la lista de chats.
  • Notificaciones push — Android: una aplicación de Android sin conexión se despierta con un push de Firebase. Cuando la aplicación se registra con account.registerDevice (token_type 2 = token de FCM, secret = clave del dispositivo de 256 bytes), el servidor cifra los mensajes y las llamadas nuevos con esa clave del dispositivo y los envía por FCM, y la aplicación, al despertar, se pone al día con updates.getDifference. Los push solo pueden llegar a aplicaciones compiladas con el proyecto de Firebase del operador del servidor.
  • Notificaciones push — iPhone: la aplicación para iPhone registra dos cosas con la misma petición: token_type 1 (token de notificaciones de APNs) y 9 (token VoIP de PushKit); en los dos casos, secret es la clave del dispositivo de 256 bytes de esa cuenta. Los mensajes nuevos van como notificaciones de APNs: el texto visible que Apple puede ver es solo el nombre de la aplicación y una frase sin contenido como «Tienes una notificación nueva», mientras que el mensaje va cifrado con la clave del dispositivo en p, y la extensión de notificaciones de la aplicación (Notification Service Extension) lo descifra y lo muestra. Las llamadas abren la pantalla de llamada de CallKit con un push VoIP (a partir de la compilación en la que el operador active VoIP; antes, como notificación), y lo que se lee o se borra en otro dispositivo se avisa con un push en segundo plano. Los push solo pueden llegar a aplicaciones firmadas por el mismo equipo que la clave de APNs del operador del servidor y con el mismo ID de paquete (bundle ID). A los demás token_type solo les responde boolTrue y no les envía nada.
  • Bibliotecas como Telethon se encargan de todo este proceso por sí solas.

IDs y peers

EntidadIDNotas
PersonasDesde 100001peerUser. @BotFather es el 100000
BotsLa misma numeración que las personasuser.bot = true. El número al principio del token es el ID del bot
Grupos básicosDesde 1000001peerChat. En la Bot API se ven como número negativo (-chat_id)
MensajesUna sola secuencia en todo el servidorLas dos copias de un chat uno a uno llevan el mismo número, así que las solicitudes que solo reciben números de mensaje, sin peer (messages.getMessages, messages.deleteMessages), apuntan al mismo mensaje para las dos personas. Solo los canales cuentan desde 1 por su cuenta

Guarda el access_hash tal como te lo da el servidor y úsalo después (llega junto con la resolución de nombres de usuario, la lista de chats y las actualizaciones).

Archivos

  • Subir: sube los fragmentos (hasta 512 KB cada uno, hasta 4.000 fragmentos) con upload.saveFilePart y haz referencia a ellos con inputFileUploaded y similares. Los archivos de más de 10 MB se suben con upload.saveBigFilePart: como se indica de antemano cuántos fragmentos son, si el tamaño supera lo que acepta el servidor la subida se rechaza con FILE_TOO_BIG antes de enviarlos todos. Los fragmentos se escriben en disco según van llegando y se unen en un solo archivo cuando un mensaje lo referencia.
  • Enviar: messages.sendMedia con inputMediaUploadedPhoto (foto nueva), inputMediaPhoto (foto que ya está en el servidor), inputMediaUploadedDocument (archivo nuevo) o inputMediaDocument (archivo que ya está en el servidor). El resto de contenido multimedia devuelve MEDIA_INVALID. También puedes subirlo sin enviarlo con messages.uploadMedia (el objeto media que devuelve se envía después tal cual), y messages.sendMultiMedia se acepta, pero los elementos van de uno en uno, sin agrupar (no hay grouped_id).
  • Recibir: upload.getFile con inputPhotoFileLocation (foto de un mensaje), inputDocumentFileLocation (archivo de un mensaje) o inputPeerPhotoFileLocation (foto de perfil). Como máximo 1 MB por llamada. Al recibir tampoco se carga el archivo entero en memoria: solo se lee el tramo solicitado.
  • Fotos de perfil: photos.uploadProfilePhoto, photos.updateProfilePhoto, photos.getUserPhotos, photos.deletePhotos.
  • Las fotos se guardan en un único tamaño, el original (no se generan miniaturas aparte). Los archivos se dejan tal cual, y los documentAttribute* que añadió quien los envió se transmiten byte a byte a quien los recibe: el servidor no necesita entender la duración de un vídeo ni la forma de onda de un audio para hacerlos llegar.

Alcance del soporte

El servidor tiene manejadores para 469 métodos de la capa 216 y todos pueden leer las peticiones, pero los que se han comprobado de principio a fin con clientes reales son los métodos de abajo. El resto responde con el formato correcto, pero puede que el contenido llegue vacío o que no se registre.

ÁreaMétodos comprobados
ConexióninitConnection, invokeWithLayer, help.getConfig, auth.bindTempAuthKey (claves temporales PFS), auth.exportAuthorization/importAuthorization
Inicio de sesiónauth.sendCode, auth.signIn, auth.signUp, auth.logOut, auth.importBotAuthorization, account.sendVerifyEmailCode
Usuarios y contactosusers.getUsers, users.getFullUser, contacts.resolveUsername, contacts.importContacts, contacts.search
Mensajesmessages.sendMessage, messages.sendMedia (fotos y archivos), messages.getHistory, messages.getDialogs, messages.getMessages, messages.editMessage, messages.deleteMessages
Gruposmessages.createChat, messages.deleteChatUser, messages.editChatTitle (messages.addChatUser solo se ha comprobado con la aplicación oficial)
Botsmessages.getBotCallbackAnswer, messages.setBotCallbackAnswer, mensajes con botones (reply_markup)
Actualizacionesupdates.getState, updates.getDifference, push en tiempo real
Archivos y fotosupload.saveFilePart, upload.saveBigFilePart (más de 10 MB), upload.getFile, photos.* (arriba)

También se ha comprobado que la aplicación oficial Telegram Desktop 6.2.6 funciona sin modificaciones en el registro, el inicio de sesión, los chats, las fotos, los grupos y la reconexión. El formato de las respuestas de los aproximadamente 60 métodos a los que llama la aplicación al arrancar se verifica aparte.

Lo añadido después —la lista de dispositivos y el cierre de sus sesiones (account.getAuthorizations, account.resetAuthorization, auth.resetAuthorizations), la exportación de datos de la aplicación de escritorio (account.initTakeoutSession, invokeWithTakeout, invokeWithMessagesRange, account.finishTakeoutSession: tres inicios al día por cuenta; por encima, 420 TAKEOUT_INIT_DELAY_n) y el cambio de número (account.sendChangePhoneCode, account.changePhone: 400 PHONE_CHANGE_DISABLED mientras el operador no lo active y BOT_METHOD_INVALID para los bots)— se ha comprobado con las pruebas del servidor; falta la comprobación de extremo a extremo con las aplicaciones reales.

Errores

Los errores llegan como el rpc_error estándar (error_code + error_message). error_message siempre tiene la forma de mayúsculas, números y guiones bajos (PEER_ID_INVALID) y, si hace falta, lleva detrás : descripción.

CódigoSignificado
400La petición es incorrecta: PEER_ID_INVALID, MESSAGE_ID_INVALID, MEDIA_INVALID, USERNAME_NOT_OCCUPIED …
401Hace falta iniciar sesión: AUTH_KEY_UNREGISTERED
403Sin permiso: por ejemplo, un grupo del que no eres miembro
406Ahora no se permite: un dispositivo con menos de 24 horas de sesión intenta cerrar la de otro, FRESH_RESET_AUTHORISATION_FORBIDDEN
420FLOOD_WAIT_n: espera n segundos
500Error interno del servidor
Error de transporte -404El servidor no conoce esta clave de autorización: crea una clave nueva y vuelve a iniciar sesión (clave permanente) o vuelve a vincularla (clave temporal)

API del reloj

/api/watch/v1/ en el servidor es un punto de entrada JSON sobre HTTPS exclusivo de la app de Pabal para Apple Watch. Existe porque el reloj no puede usar MTProto; no es una especificación pública y está en preparación, así que puede cambiar sin previo aviso. Si quieres crear un programa que se conecte a Pabal, usa el MTProto de esta página. Quienes operan un servidor pueden consultar Instalar el servidor: punto de entrada del Apple Watch.

Lo que todavía no existe

  • Canales y supergrupos (channels.* responde, pero no se muestra bien en la aplicación), chats secretos, llamadas de grupo
  • Mensajes de vídeo y de voz que se reproducen dentro de la aplicación, álbumes mostrados como un solo bloque (grouped_id), stickers, miniaturas (de los archivos solo se guarda el original)
  • Verificación en dos pasos (SRP): no se puede configurar, y las operaciones que la requieren se rechazan
  • Transportes HTTP y WebSocket, MTProxy, envío de msgs_ack, rotación periódica de la sal del servidor (una sal errónea recibe bad_server_salt)
  • Repartir la carga entre varios servidores: un solo servidor atiende todos los DC del 1 al 5

Para conectar la aplicación oficial de Telegram a Pabal

La aplicación de Telegram incorpora la dirección del servidor y la clave pública al compilarse. Por eso no se cambia desde la pantalla de ajustes: hay que modificar el código fuente y volver a compilarla. Así es como se hizo la aplicación Pabal (Pabal.app). Si operas un servidor, consulta Instalar el servidor — Conectar la aplicación.