Manipulador externo
O manipulador externo é uma ponte entre seu código e o Telegram. Quando a lógica do construtor não é suficiente, você delega uma reação específica ao seu servidor: ele recebe eventos e responde com comandos no formato da Telegram Bot API, enquanto o GetMyBot cuida do transporte, da entrega e de toda a comunicação com o Telegram.
O que é isso
As reações no GetMyBot são montadas visualmente: gatilho → condições → ações. Lógica complexa ou não convencional — sua própria base de dados, cálculos, chamadas a sistemas externos, ML, cenários ramificados — é difícil de expressar no construtor. O manipulador externo remove esse limite: você conecta seu próprio backend e delega a ele o processamento de reações inteiras.
O serviço externo recebe do GetMyBot eventos (gatilho acionado, usuário respondeu com texto, clicou em botão) e, em resposta, instrui o bot sobre o que enviar. O GetMyBot executa os comandos com seu próprio token de bot — por cima funcionam rate-limit, retentativas, deduplicação e histórico de diálogo.
Modelo de funcionamento
- GetMyBot é o servidor WebSocket. Seu serviço se conecta a ele e não precisa de um endereço público nem de um endpoint de webhook. O GetMyBot não faz conexões de saída para o seu serviço, portanto não há superfície de ataque SSRF.
- Autenticação por token de integração. O serviço apresenta o token ao conectar; o GetMyBot o verifica com o hash e mantém a conexão.
- Eventos e comandos no formato da Telegram Bot API. O serviço recebe um evento e responde com um array de chamadas no formato "método + parâmetros", exatamente como ao trabalhar com um bot comum.
- Os comandos são executados pelo GetMyBot com seu próprio token. O serviço nunca se comunica com o Telegram diretamente: os comandos passam por validação e entram no outbox interno do GetMyBot, de onde são enviados com o token do bot com rate-limit, retentativas, deduplicação e histórico.
Uma única conexão atende a todos os diálogos de uma integração — eventos de diferentes usuários são multiplexados e distinguidos pelo campo session_id.
Configurar a integração
- Abra a seção Integrações no menu à esquerda e clique em Adicionar integração.
- Escolha o serviço Manipulador externo e defina um nome.
- Após a criação, o cartão exibirá:
- Endereço WebSocket — no formato
wss://api.mybot.app/ext/ws/<integrationID>, onde<integrationID>é o UUID desta integração. É por esse endereço que seu serviço se conecta. Sem o id no caminho, a conexão não será estabelecida. - Token de conexão — exibido uma única vez na criação. Copie e guarde em local seguro; não é possível visualizar o token novamente (ele é armazenado apenas como hash).
- Rotacionar token — o botão gera um novo token e invalida imediatamente o anterior. Após a rotação, atualize o token no seu serviço.
- Indicador online — mostra se o seu serviço mantém uma conexão ativa no momento.
- Endereço WebSocket — no formato
Parâmetros adicionais da integração que afetam o protocolo:
session_ttl_seconds— tempo de vida da sessão em segundos (padrão:3600).on_unavailable_reaction_id— reação de fallback que é iniciada se o serviço estiver offline no momento do acionamento (veja Confiabilidade).
Vinculação a uma reação
O manipulador externo é conectado não como um gatilho separado, mas como uma ação. No editor de reação, adicione a ação Transferir para manipulador externo e selecione a integração desejada.
O diálogo pode ser iniciado por qualquer gatilho existente do GetMyBot — comando, texto, clique em botão, parâmetro de link, requisição web de entrada, agendamento. Quando esse gatilho é acionado e chega à ação, o GetMyBot abre uma sessão proxy e envia ao serviço o evento session.open.
Se nesse momento o serviço não estiver conectado, o GetMyBot iniciará a reação de fallback definida nas configurações da integração (on_unavailable_reaction_id). Se nenhuma reação de fallback estiver definida, nada acontecerá (silenciosamente, sem erro para o usuário).
Conexão e autorização
Endpoint: GET /ext/ws/{integrationID} sobre WebSocket (wss). integrationID é o UUID da integração do tipo "Manipulador externo". Limite de tamanho de frame: 256 KiB.
A autorização pode ser feita de duas maneiras.
1. Cabeçalho no handshake (preferencial). Passe o token no cabeçalho Authorization:
Authorization: Bearer <token>
2. Frame de auth. Se o cabeçalho Bearer não for enviado, envie como primeiro frame dentro de 10 segundos após a conexão ser estabelecida:
{ "type": "auth", "token": "<token>" }
Se o frame de auth não chegar em 10 segundos, a conexão será fechada com código 4401. Um token inválido em qualquer uma das formas também resulta em close 4401.
O token é gerado na criação da integração, exibido uma única vez e armazenado apenas como hash (sha256); a verificação é feita em tempo constante. Rotação do token:
POST /api/bots/{botID}/integrations/{integrationID}/rotate-token
O endpoint retorna o novo token em texto simples; o anterior para de funcionar imediatamente.
Eventos: bot → serviço
Cada evento é um frame JSON (EventEnvelope). O campo type é um de: session.open, message, callback, session.cancel, session.expired.
Conjunto completo de campos do envelope:
{
"type": "session.open",
"session_id": "string",
"bot_id": "string",
"user": {
"tg_user_id": 123456789,
"first_name": "Ivan",
"username": "ivan",
"params": { "utm": "promo" }
},
"chat": { "id": 123456789, "type": "private" },
"update": { "...": "raw Telegram Update (raw JSON)" },
"event": { "...": "evento normalizado do GetMyBot (raw JSON)" }
}
session_id— identificador da sessão (diálogo).bot_id— identificador do bot.user— dados do usuário:tg_user_id(int64),first_nameeusernameopcionais, além deparams— parâmetros do usuário (incluindo os de link), map chave→valor.chat— chat:id(int64) etype(por exemplo"private").update— Telegram Update bruto (raw JSON). Presente emsession.open,message,callback.event— evento normalizado do GetMyBot (raw JSON).
O conteúdo varia por tipo:
session.open— gatilho acionado, novo diálogo aberto. Incluiupdate(Update bruto) eevent(evento normalizado completo);user.paramspreenchidos.message— enviado quando o serviço está "aguardando" (expect=text/any) e o usuário enviou uma mensagem. Mesmo conteúdo quesession.open.callback— o usuário clicou em um botão enviado anteriormente pelo serviço.updateé bruto; emuserapenastg_user_idé preenchido;eventcontém apenas o callback_data original definido pelo serviço no botão:
{ "callback_data": "<valor original definido pelo serviço no botão>" }
session.cancel/session.expired— envelope mínimo:session_id,bot_id,user.tg_user_id,chat.id(paracancel, tambémchat.type). Camposupdate/eventausentes. Esses eventos são entregues apenas se o serviço estiver online — não são colocados na fila offline.
Comandos: serviço → bot
Um comando é um frame JSON (CommandEnvelope). O campo type é um de: execute, session.close, auth, ping, pong.
{
"type": "execute",
"session_id": "string",
"methods": [
{ "method": "sendMessage", "params": { "text": "Olá" } }
],
"expect": "none"
}
session_id— a sessão à qual o comando pertence.token— apenas paratype: "auth"(veja Conexão e autorização).methods— array de objetos{ "method": "<nome do método da Telegram Bot API>", "params": { ... } }. O nome do método é exatamente como na Telegram Bot API (por exemplosendMessage);paramsé o objeto de parâmetros desse método.expect— se o serviço aguarda resposta do usuário:"none","text"ou"any"(valor vazio é tratado comonone).session.close— fecha explicitamente o diálogo.
Os comandos não vão ao Telegram diretamente: o GetMyBot os valida e os coloca no outbox interno, de onde são enviados com o token do bot (com rate-limit, retentativas, deduplicação e histórico).
Como o execute é processado
O comando execute é descartado inteiramente se: session_id estiver vazio; a sessão não for encontrada ou não estiver com status open; a sessão pertencer a outra integração; a sessão estiver expirada.
Em seguida:
- Rate-limit: até 60
executepor minuto por sessão (janela deslizante). Acima do limite — descartado. - Até 30 métodos em um único
execute; os excedentes são silenciosamente ignorados. - Cada método é verificado contra a lista de permissões (veja Métodos permitidos) — métodos fora da lista são rejeitados.
- Chat-guard: se
paramscontiverchat_idoufrom_chat_idcom valor diferente de0e diferente dochat_idda sessão, o método inteiro é rejeitado (não é permitido enviar para outro chat).chat_idpode ser omitido: o GetMyBot preencherá automaticamente com o chat da sessão. - Botões inline com
callback_datasão tokenizados automaticamente (formato internox:<token>); o tempo de vida do botão é até o fim da sessão. Botõesurl/webapp/switch_inlinenão são alterados.
Métodos permitidos
O serviço comanda o bot, por isso o conjunto de métodos é limitado a uma lista de permissões — apenas envio e manipulação de mensagens do diálogo atual. Métodos fora da lista são silenciosamente ignorados (não é um erro).
- envio:
sendMessage,sendPhoto,sendDocument,sendVideo,sendAudio,sendMediaGroup,sendAnimation,sendVoice,sendLocation,sendChatAction; - edição e exclusão:
editMessageText,editMessageCaption,editMessageReplyMarkup,deleteMessage; - resposta a clique:
answerCallbackQuery; - encaminhamento e cópia:
forwardMessage,copyMessage; - fixar/desafixar:
pinChatMessage,unpinChatMessage.
Métodos de nível de conta (setWebhook, getUpdates, logOut, close, setMyCommands etc.) não são permitidos.
Aguardo e ciclo de vida da sessão
Após cada execute, o destino da sessão depende de expect e de se havia botões inline com callback_data no comando:
expect=textouany— a próxima mensagem do usuário será encaminhada ao serviço como eventomessage.expect=noneE o comando NÃO tinha botões inline com callback — a sessão é fechada automaticamente. Esta é a mensagem "terminal".expect=none, MAS há botões com callback — a sessão permanece aberta: os cliques são capturados enquanto os tokens dos botões estiverem vivos (até o TTL).
Importante: expect não afeta o recebimento de cliques em botões. Cliques em botões tokenizados são capturados independentemente do valor de expect — enquanto a sessão e o token do botão estiverem vivos. expect controla apenas se o serviço aguarda uma resposta de texto/qualquer tipo.
Limites do diálogo
O contexto do diálogo existe exatamente enquanto a sessão estiver aberta:
- Resposta de texto com aguardo ativo (
expect=text/any) — vai ao serviço como eventomessage, sem acionar as reações normais do bot. - Clique em botão tokenizado — vai ao serviço como evento
callbackcom ocallback_dataoriginal. O GetMyBot sempre confirma o clique automaticamente (answerCallbackQuery); verifica-se o pertencimento do clique (bot + usuário + chat da sessão). Um clique em botão não fecha a sessão. /cancel(também/cancel@bote "cancelar") durante uma sessão externa ativa — a sessão é fechada, o serviço recebesession.cancele o usuário recebe "Cancelado.".- Um diálogo por usuário. Abrir uma nova sessão substitui a sessão anterior aberta desse usuário — ela recebe
session.cancel. - Expiração do TTL. Por temporizador, a sessão é marcada como
expirede (se o serviço estiver online) o serviço recebesession.expired.
Limites e timeouts
- Tamanho do frame: 256 KiB.
- TTL da sessão: padrão 3600 segundos (configurável pelo parâmetro
session_ttl_secondsda integração). - Frequência de comandos: 60
executepor minuto por sessão (janela deslizante). - Métodos por
execute: até 30 (os excedentes são descartados). - Sessões abertas por integração: até 1000.
- Fila offline: até 100 eventos por sessão.
- Heartbeat:
pinga cada 30 segundos; timeout de inatividade — 60 segundos. - Timeout do frame de auth: 10 segundos.
Confiabilidade (heartbeat, offline, fila, fallback)
- Heartbeat. O servidor envia um frame
{"type":"ping"}a cada 30 segundos. Se não houver atividade do cliente por mais de 60 segundos, a conexão é fechada. O cliente pode enviar seus própriosping/pongpara manter a atividade. A queda de conexão não encerra os diálogos: as sessões vivem no banco de dados até o TTL ou a reconexão. - Reconexão — responsabilidade do serviço. Se a conexão cair, seu serviço deve se reconectar. Sessões abertas no banco de dados sobrevivem a reinicializações até o TTL expirar.
- Fallback quando offline na partida. Se no momento do acionamento da reação o serviço não estiver conectado — a reação de fallback das configurações da integração é iniciada (
on_unavailable_reaction_id). Se não estiver definida — nada acontece (silenciosamente). - Fila offline. Eventos
message/callbacknão entregues por causa do offline são colocados na fila offline (até 100 eventos, FIFO, armazenados até o fim da sessão) e entregues na reconexão. Eventossession.open/session.cancel/session.expirednão são colocados na fila. - Garantia de entrega — at-most-once. Em caso de overflow ou expiração da fila, os eventos são descartados. Projete sua lógica de forma que a perda de um evento individual não quebre o cenário.
Indicador online
Para verificar se o serviço mantém uma conexão ativa, use o endpoint:
GET /api/bots/{botID}/integrations/{integrationID}/status
Resposta:
{ "online": true }
O mesmo indicador está disponível no cartão da integração no painel. O equivalente no MCP é a ferramenta get_integration_status.
Segurança
O GetMyBot executa comandos de um serviço externo com seu próprio token, por isso a proteção é rigorosa.
- Sem superfície SSRF. O GetMyBot atua como servidor WebSocket e não faz conexões de saída para o serviço — é o serviço que se conecta ao GetMyBot. Não há URL controlada externamente para onde a plataforma faça requisições.
- Token armazenado como hash (sha256), verificação em tempo constante, rotação suportada.
- Isolamento de tenant. O comando está rigidamente vinculado à sua integração; a sessão está vinculada ao bot + usuário + chat. Eventos de outros bots não chegam ao seu socket.
- Lista de permissões de métodos +
chat_idforçado impedem que o bot seja usado como remetente para chats arbitrários. - O token do bot não é exposto externamente — o serviço nunca se comunica com o Telegram diretamente.
- Mascaramento de segredos. O token de integração e valores sensíveis são ocultados no histórico e nos logs.
Exemplos
Manipulador mínimo: ao abrir o diálogo, envia uma mensagem e fecha a sessão (expect: "none"). Substitua o id da integração e o token. O endereço deve obrigatoriamente conter <integrationID> no caminho.
Node.js
import WebSocket from "ws";
const URL = `wss://api.mybot.app/ext/ws/${process.env.MYBOT_INTEGRATION_ID}`;
const ws = new WebSocket(URL, {
headers: { Authorization: `Bearer ${process.env.MYBOT_TOKEN}` },
});
ws.on("message", (raw) => {
const ev = JSON.parse(raw);
if (ev.type === "session.open") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{ method: "sendMessage", params: { text: "Olá do manipulador externo!" } }],
}));
}
});
Python
import json, os, asyncio, websockets
async def main():
url = f"wss://api.mybot.app/ext/ws/{os.environ['MYBOT_INTEGRATION_ID']}"
headers = {"Authorization": f"Bearer {os.environ['MYBOT_TOKEN']}"}
async with websockets.connect(url, additional_headers=headers) as ws:
async for raw in ws:
ev = json.loads(raw)
if ev["type"] == "session.open":
await ws.send(json.dumps({
"type": "execute",
"session_id": ev["session_id"],
"expect": "none",
"methods": [
{"method": "sendMessage", "params": {"text": "Olá do manipulador externo!"}}
],
}))
asyncio.run(main())
Botão inline e processamento de callback
Para capturar um clique, envie um botão com callback_data (o GetMyBot o tokeniza automaticamente). Com expect: "none" e um botão presente, a sessão permanece aberta enquanto o token do botão estiver vivo — o clique chegará como evento callback, no qual event.callback_data é igual ao valor original. Não é necessário confirmar o clique (answerCallbackQuery) — o GetMyBot faz isso automaticamente.
if (ev.type === "session.open") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{
method: "sendMessage",
params: {
text: "Clique no botão",
reply_markup: { inline_keyboard: [[{ text: "Vamos lá", callback_data: "go" }]] },
},
}],
}));
} else if (ev.type === "callback" && ev.event.callback_data === "go") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{ method: "sendMessage", params: { text: "Botão clicado!" } }],
}));
}
O que vem a seguir
- Integrações — visão geral dos serviços conectáveis.
- Reações — como são montados gatilhos, condições e ações.
- Requisições web e webhooks — forma mais simples de chamar uma URL externa sem diálogo.