Plugin — Telegram Bot
Plugin — Telegram Bot
El plugin de Telegram convierte mensajes de texto y notas de voz recibidos en un bot en tareas cascarón. Opera vía webhook: Telegram envía un POST al endpoint de Joe por cada actualización.
Endpoint del webhook
| Propiedad | Valor |
|---|---|
| Método | POST |
| Ruta | /plugins/telegram/webhook/{plugin_id}/ |
| Parámetro | Ubicación | Descripción |
|---|---|---|
plugin_id |
Path | ID del PluginConfig registrado para este bot. |
X-Telegram-Bot-Api-Secret-Token |
Header | Token secreto configurado al registrar el webhook en Telegram. |
Configuración paso a paso
-
Crear el bot en Telegram con BotFather
/newbot # Sigue las instrucciones, BotFather te entrega: # Token: 1234567890:ABCDefghIJKlmnOPQrsTUVwxyz -
Registrar el PluginConfig en Joe
from apps.common.models import PluginConfig config = PluginConfig( usuario=user, servicio="telegram", identificador="@joe_bot", metadatos={"webhook_secret": "mi_secret_seguro_aleatorio"}, ) config.set_token("1234567890:ABCDefghIJKlmnOPQrsTUVwxyz") config.save() # Anota el ID generado: config.pk → ej. 3 # Anota el código de verificación: config.codigo_verificacion → ej. JOE-A1B2 -
Registrar el webhook en Telegram
POST https://api.telegram.org/bot<TOKEN>/setWebhook Content-Type: application/json { "url": "https://joe.pedroospino.net/plugins/telegram/webhook/3/", "secret_token": "mi_secret_seguro_aleatorio" }import requests TOKEN = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz" resp = requests.post( f"https://api.telegram.org/bot{TOKEN}/setWebhook", json={ "url": "https://joe.pedroospino.net/plugins/telegram/webhook/3/", "secret_token": "mi_secret_seguro_aleatorio" } ) print(resp.json()) # {"ok": true, "result": true, ...}const TOKEN = '1234567890:ABCDefghIJKlmnOPQrsTUVwxyz'; const { data } = await axios.post( `https://api.telegram.org/bot${TOKEN}/setWebhook`, { url: 'https://joe.pedroospino.net/plugins/telegram/webhook/3/', secret_token: 'mi_secret_seguro_aleatorio' } );var token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; var body = new StringContent( JsonSerializer.Serialize(new { url = "https://joe.pedroospino.net/plugins/telegram/webhook/3/", secret_token = "mi_secret_seguro_aleatorio" }), Encoding.UTF8, "application/json" ); var response = await client.PostAsync( $"https://api.telegram.org/bot{token}/setWebhook", body);String token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telegram.org/bot" + token + "/setWebhook")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString( "{\"url\":\"https://joe.pedroospino.net/plugins/telegram/webhook/3/\"," + "\"secret_token\":\"mi_secret_seguro_aleatorio\"}" )) .build();Respuesta esperada:
{"ok": true, "result": true, "description": "Webhook was set"} -
Verificar el webhook
GET https://api.telegram.org/bot<TOKEN>/getWebhookInfoimport requests TOKEN = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz" resp = requests.get(f"https://api.telegram.org/bot{TOKEN}/getWebhookInfo") print(resp.json())const TOKEN = '1234567890:ABCDefghIJKlmnOPQrsTUVwxyz'; const { data } = await axios.get( `https://api.telegram.org/bot${TOKEN}/getWebhookInfo` );var token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; var response = await client.GetAsync( $"https://api.telegram.org/bot{token}/getWebhookInfo");String token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telegram.org/bot" + token + "/getWebhookInfo")) .GET() .build(); -
Vincular el chat (Soberanía del Usuario)
Abre el bot en Telegram y envía el comando de verificación con el
codigo_verificaciondel paso anterior:/start JOE-A1B2El bot responderá: "✅ ¡Bot vinculado con éxito! Ya puedes enviarme notas de voz o texto."
Hasta completar este paso, cualquier mensaje recibido será rechazado con un aviso.
PluginConfig puede vincular un chat. El código JOE-XXXX es único por registro y se genera automáticamente al crear el plugin.
Flujo de un mensaje entrante
- Telegram envía
POSTal webhook con el update JSON. - Joe valida el header
X-Telegram-Bot-Api-Secret-Tokencontra elwebhook_secretalmacenado. - Se deserializa el payload (
TelegramUpdate). - Si el mensaje es
/start JOE-XXXX: se valida el código, se estableceverificado=Truey se guarda elchat_id_verificado. - Si el plugin no está verificado: el bot avisa al usuario y descarta el mensaje (sin crear tarea).
- Si es texto: se crea una tarea con
tipo=telegramy el texto como título. - Si es voz: se crea una tarea con
tipo=telegram_voiceypendiente_stt=Trueen metadatos. - Joe responde
{"ok": true}con HTTP 200 (evita reintentos de Telegram). - El bot envía un mensaje de confirmación al chat: "✅ Recibido. Encolando... [CODIGO]"
Campos en metadatos_extra de la tarea
| Campo | Descripción |
|---|---|
chat_id | ID del chat de Telegram. Necesario para responder. |
message_id | ID del mensaje en Telegram. |
plugin_id | ID del PluginConfig que procesó el mensaje. |
owner_id | ID del usuario dueño del plugin. |
texto_original | Texto completo del mensaje (solo en tareas de texto). |
pendiente_stt | true si es una nota de voz pendiente de transcripción. |
Campos del PluginConfig para Telegram
| Campo | Valor esperado |
|---|---|
servicio | "telegram" |
identificador | Username del bot: @joe_bot |
token_cifrado | Bot token de BotFather (cifrado con Fernet) |
metadatos.webhook_secret | String aleatorio seguro. Se envía a Telegram al registrar el webhook. |
codigo_verificacion | Generado automáticamente (ej. JOE-A1B2). El usuario lo usa en /start. |
verificado | False hasta que el usuario complete el flujo /start. |
chat_id_verificado | null hasta la verificación. Luego contiene el ID del chat vinculado. |
The Telegram plugin converts text messages and voice notes received by a bot into shell tasks. It operates via webhook: Telegram sends a POST to Joe's endpoint for each update.
Webhook endpoint
| Property | Value |
|---|---|
| Method | POST |
| Path | /plugins/telegram/webhook/{plugin_id}/ |
| Parameter | Location | Description |
|---|---|---|
plugin_id |
Path | ID of the PluginConfig registered for this bot. |
X-Telegram-Bot-Api-Secret-Token |
Header | Secret token configured when registering the webhook in Telegram. |
Step-by-step configuration
-
Create the bot in Telegram with BotFather
/newbot # Follow the instructions, BotFather gives you: # Token: 1234567890:ABCDefghIJKlmnOPQrsTUVwxyz -
Register the PluginConfig in Joe
from apps.common.models import PluginConfig config = PluginConfig( usuario=user, servicio="telegram", identificador="@joe_bot", metadatos={"webhook_secret": "my_secure_random_secret"}, ) config.set_token("1234567890:ABCDefghIJKlmnOPQrsTUVwxyz") config.save() # Note the generated ID: config.pk → e.g. 3 # Note the verification code: config.codigo_verificacion → e.g. JOE-A1B2 -
Register the webhook in Telegram
POST https://api.telegram.org/bot<TOKEN>/setWebhook Content-Type: application/json { "url": "https://joe.pedroospino.net/plugins/telegram/webhook/3/", "secret_token": "my_secure_random_secret" }import requests TOKEN = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz" resp = requests.post( f"https://api.telegram.org/bot{TOKEN}/setWebhook", json={ "url": "https://joe.pedroospino.net/plugins/telegram/webhook/3/", "secret_token": "my_secure_random_secret" } ) print(resp.json()) # {"ok": true, "result": true, ...}const TOKEN = '1234567890:ABCDefghIJKlmnOPQrsTUVwxyz'; const { data } = await axios.post( `https://api.telegram.org/bot${TOKEN}/setWebhook`, { url: 'https://joe.pedroospino.net/plugins/telegram/webhook/3/', secret_token: 'my_secure_random_secret' } );var token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; var body = new StringContent( JsonSerializer.Serialize(new { url = "https://joe.pedroospino.net/plugins/telegram/webhook/3/", secret_token = "my_secure_random_secret" }), Encoding.UTF8, "application/json" ); var response = await client.PostAsync( $"https://api.telegram.org/bot{token}/setWebhook", body);String token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telegram.org/bot" + token + "/setWebhook")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString( "{\"url\":\"https://joe.pedroospino.net/plugins/telegram/webhook/3/\"," + "\"secret_token\":\"my_secure_random_secret\"}" )) .build();Expected response:
{"ok": true, "result": true, "description": "Webhook was set"} -
Verify the webhook
GET https://api.telegram.org/bot<TOKEN>/getWebhookInfoimport requests TOKEN = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz" resp = requests.get(f"https://api.telegram.org/bot{TOKEN}/getWebhookInfo") print(resp.json())const TOKEN = '1234567890:ABCDefghIJKlmnOPQrsTUVwxyz'; const { data } = await axios.get( `https://api.telegram.org/bot${TOKEN}/getWebhookInfo` );var token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; var response = await client.GetAsync( $"https://api.telegram.org/bot{token}/getWebhookInfo");String token = "1234567890:ABCDefghIJKlmnOPQrsTUVwxyz"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telegram.org/bot" + token + "/getWebhookInfo")) .GET() .build(); -
Link the chat (User Sovereignty)
Open the bot in Telegram and send the verification command with the
codigo_verificacionfrom the previous step:/start JOE-A1B2The bot will reply: "✅ Bot linked successfully! You can now send me voice notes or text."
Until this step is completed, any received message will be rejected with a warning.
PluginConfig can link a chat. The JOE-XXXX code is unique per record and auto-generated when creating the plugin.
Incoming message flow
- Telegram sends
POSTto the webhook with the update JSON. - Joe validates the
X-Telegram-Bot-Api-Secret-Tokenheader against the storedwebhook_secret. - The payload is deserialized (
TelegramUpdate). - If the message is
/start JOE-XXXX: the code is validated,verificado=Trueis set, andchat_id_verificadois saved. - If the plugin is not verified: the bot warns the user and discards the message (no task is created).
- If text: a task is created with
tipo=telegramand the text as title. - If voice: a task is created with
tipo=telegram_voiceandpendiente_stt=Truein metadata. - Joe responds
{"ok": true}with HTTP 200 (prevents Telegram retries). - The bot sends a confirmation message to the chat: "✅ Received. Queuing... [CODE]"
Fields in task metadatos_extra
| Field | Description |
|---|---|
chat_id | Telegram chat ID. Required to reply. |
message_id | Message ID in Telegram. |
plugin_id | PluginConfig ID that processed the message. |
owner_id | ID of the plugin's owner user. |
texto_original | Full message text (text tasks only). |
pendiente_stt | true if it's a voice note pending transcription. |
PluginConfig fields for Telegram
| Field | Expected value |
|---|---|
servicio | "telegram" |
identificador | Bot username: @joe_bot |
token_cifrado | BotFather bot token (Fernet-encrypted) |
metadatos.webhook_secret | Secure random string. Sent to Telegram when registering the webhook. |
codigo_verificacion | Auto-generated (e.g. JOE-A1B2). Used by the user in /start. |
verificado | False until the user completes the /start flow. |
chat_id_verificado | null until verification. Then holds the linked chat ID. |