Documentación · Bot API

Bots de Koto en cualquier lenguaje

Una API HTTP sencilla. Envías HTTP + JSON normal; la pasarela de Koto mantiene la identidad E2E del bot y su bandeja de entrada, descifra los mensajes entrantes y convierte tus llamadas en operaciones cifradas de Koto. Tú no tocas la criptografía.

Resumen

La API sigue un patrón familiar: el método es la ruta, el token va en una cabecera Authorization y la respuesta es un envoltorio JSON { ok, result }. No se requiere ningún SDK: solo necesitas hacer peticiones HTTP. El formato de las llamadas es compatible con las bibliotecas cliente existentes de la Telegram Bot API*, por lo que a menudo basta con redirigir su URL base a la pasarela de Koto.

El flujo es sencillo: crea un bot en @BotKoto y obtén un token → llama a los métodos pasando el token en una cabecera Authorization → recibe actualizaciones por long-poll getUpdates o un webhook.

* Telegram es una marca comercial de Telegram Messenger LLP. Koto se desarrolla de forma independiente, no está afiliado ni respaldado por Telegram; el nombre se utiliza únicamente para describir la compatibilidad.

1. Crear un bot

Abre @BotKoto en cualquier cliente de Koto, envía /newbot, elige un nombre y @username. Recibirás un token como kbot_0a1b2c…. Mantenlo en secreto: controla el bot.

2. Llamar a la API

El método es la ruta completa; el token va en una cabecera Authorization: Bearer (nunca en la URL, para que no se filtre en los registros):

endpoint
# the method is the whole path; the token rides in a header
{GATEWAY}/{method}
Authorization: Bearer {TOKEN}

# example
curl -H "Authorization: Bearer kbot_0a1b…" \
  https://api.koto.run/getMe

Cada respuesta es un envoltorio JSON:

envelope
{ "ok": true,  "result":  }
{ "ok": false, "error": "reason" }

Una comprobación rápida de que el bot está activo:

getMe
curl -H "Authorization: Bearer kbot_0a1b…" \
  https://api.koto.run/getMe
# {"ok":true,"result":{"id":"bot-…","username":"mybot","is_bot":true}}

Enviar un mensaje:

sendMessage
curl -X POST https://api.koto.run/sendMessage \
  -H "Authorization: Bearer kbot_…" \
  -H 'content-type: application/json' \
  -d '{"chat_id":"KOTO-…","text":"Hello from Koto!"}'

3. Recibir actualizaciones

Dos formas mutuamente excluyentes:

Long-poll getUpdates — extrae actualizaciones y confírmalas con un offset creciente. offset = último update_id + 1 confirma todo lo anterior. getUpdates mantiene la conexión hasta timeout segundos (25 por defecto).

Webhook setWebhook — la propia pasarela hace POST de cada actualización a tu URL. Mientras haya un webhook configurado, getUpdates devuelve 409.

Ejemplo: bot de eco

Un bot completo en bash puro: solo HTTP + JSON, sin SDK de Koto y sin criptografía. Long-poll getUpdates y respuesta mediante sendMessage:

echo.sh
#!/usr/bin/env bash
# A full bot over plain HTTP — no SDK, no crypto. The token rides in an
# Authorization: Bearer header, never the URL.
# Run:  BOT_TOKEN=kbot_xxx ./echo.sh
API="http://127.0.0.1:8090"
AUTH=(-H "Authorization: Bearer $BOT_TOKEN")

offset=0
while true; do
  resp=$(curl -s "${AUTH[@]}" "$API/getUpdates?offset=$offset&timeout=20")
  for upd in $(echo "$resp" | jq -c '.result[]?'); do
    offset=$(( $(jq '.update_id' <<<"$upd") + 1 ))
    chat=$(jq -r '.message.chat.id // ""' <<<"$upd")
    text=$(jq -r '.message.text // ""' <<<"$upd")
    [ -n "$chat" ] && [ -n "$text" ] && \
      curl -s -X POST "${AUTH[@]}" "$API/sendMessage" -H 'content-type: application/json' \
        -d "$(jq -nc --arg c "$chat" --arg t "Echo: $text" '{chat_id:$c,text:$t}')"
  done
done

Métodos

chat_id es lo que llegó en message.chat.id de la actualización. Los identificadores de mensaje son cadenas opacas. Un envío correcto devuelve { "message_id": "…" }, una operación void devuelve true.

Lectura

MétodoHTTPParámetrosResultado
getMeGET{ id, username, is_bot }
getUpdatesGET?offset= &timeout= &limit=matriz de Update
getChatGET?chat_id={ id, type, members }

Envío y acciones

MétodoCuerpoNotas
sendMessage{ chat_id, text, reply_markup?, reply_to_message_id? }texto, teclado en línea opcional y respuesta citada
sendPhoto{ chat_id, photo, mime, w, h, caption? }photo — base64 de los bytes de la imagen
sendDocument{ chat_id, document, file_name, mime, size }document — base64 del archivo
editMessageText{ chat_id, message_id, text }editar el texto
editMessageReplyMarkup{ chat_id, message_id, reply_markup }un markup vacío quita el teclado
deleteMessage{ chat_id, message_id }eliminar
forwardMessage{ chat_id, text, from? }from — la etiqueta «reenviado de»
sendPoll{ chat_id, question, options[], is_anonymous? }encuesta
pinChatMessage{ chat_id, message_id }fijar
unpinChatMessage{ chat_id }desfijar
setMessageReaction{ chat_id, message_id, emoji, add? }add por defecto es true
sendChatAction{ chat_id, action? }muestra «escribiendo…»
answerCallbackQuery{ callback_query_id }ack no-op (Koto no tiene spinner en el botón)

Menú de comandos (la lista «/»)

MétodoCuerpoNotas
setMyCommands{ commands: [{ command, description }] }lista pública de comandos
getMyCommandslista actual
deleteMyCommandsvaciar

Webhooks

MétodoCuerpoNotas
setWebhook{ url, secret_token? }la pasarela hace POST de las actualizaciones a url; secret_token se devuelve como X-Bot-Webhook-Secret
deleteWebhookvuelve a getUpdates
getWebhookInfo{ url, pending_update_count, … }

El objeto Update

getUpdates (y el cuerpo del POST del webhook) devuelven un Update. Se rellena exactamente un campo de datos por actualización:

Update
{
  "update_id": 42,
  "message":          {  },   // new incoming message
  "edited_message":   {  },   // a message's text was edited
  "callback_query":   {  },   // inline button press
  "poll_answer":      {  },   // poll vote
  "message_reaction": {  }    // reaction toggled
}

Message

Message
{
  "message_id": "…",
  "date": 1733836800,
  "chat": { "id": "…" },
  "from": { "id": "KOTO-…" },
  "text": "hello",
  "caption": "…",                                  // for a photo/document
  "photo":    { "data": "<base64>", "mime": "image/jpeg", "w": 1280, "h": 720 },
  "document": { "data": "<base64>", "file_name": "…", "mime": "…", "size": 1234 },
  "reply_to_message": {  },                       // if this is a quoted reply
  "forward_from": "Alice",                         // if forwarded
  "reply_markup": [[  ]]                          // attached keyboard
}

callback_query: { id, from, chat, message_id, data } — pasa chat.id a sendMessage para responder a la pulsación.

Botones en línea

reply_markup son filas de botones. Cada botón es { text, data }:

reply_markup
{
  "chat_id": "KOTO-…",
  "text": "Choose an option",
  "reply_markup": [
    [ { "text": "Yes", "data": "y" }, { "text": "No", "data": "n" } ]
  ]
}

Una pulsación llega como una actualización callback_query con el campo data del botón pulsado. Puedes responder a ella llamando a answerCallbackQuery (en Koto un ack inofensivo) y enviando un mensaje al chat.id del callback.

Mini aplicaciones

Una mini aplicación es una página web que el bot abre dentro de un chat de Koto. El usuario pulsa el botón de la aplicación (▦) junto al campo de entrada, la página se carga en un entorno aislado y puede comunicarse con el bot. La URL debe ser HTTPS.

Indicar la URL de la mini aplicación

A través de un cliente de Koto (bot → Mini App → pegar la URL) o a través del registro con el token de gestión del bot:

registry
PUT /v1/bots/<token>/webapp     {"url": "https://example.com/app"}

El puente KotoWebApp

index.html
<script src="koto-webapp.js"></script>
<script>
  KotoWebApp.ready();                       // theme + platform from the host
  KotoWebApp.MainButton.setText("Done").show();
  KotoWebApp.MainButton.onClick(function () {
    KotoWebApp.sendData(JSON.stringify({ ok: true }));  // → sent to the bot
  });
</script>
MiembroQué hace
ready()informar al host de que la página se ha cargado; rellena themeParams/platform
sendData(string)enviar una cadena al bot, luego la aplicación se cierra
close() / expand()cerrar / expandir la hoja a toda la altura
openLink(url)abrir una URL en el navegador del usuario
themeParamscolores del host (también como variables CSS --koto-*)
MainButton.setText .show .hide .enable .disable .onClick
onEvent(name, cb)eventos: ready, themeChanged, mainButtonClicked

sendData(s) entrega s al bot como un mensaje entrante normal (el bot lo ve a través de getUpdates/webhook). Envía JSON compacto y analízalo en el bot.

Límites y particularidades

  • Límite de tasa: por bot, 30 peticiones/seg por defecto → 429 si se supera.
  • Multimedia — base64 en línea: envía los bytes directamente en photo / document, sin carga en dos pasos ni file_id.
  • Los identificadores son Koto ID (KOTO-… para usuarios, bot-… para bots), no numéricos.
  • End-to-end: los mensajes se cifran en tránsito, el relé ciego nunca ve el texto plano. La pasarela descifra en nombre del bot, por lo que el operador del bot (y la pasarela que lo aloja) ven lo que se escribe al bot. Los chats con un bot no son privados frente al propio bot. Esto no afecta a las conversaciones usuario↔usuario.

Estado de funciones

FunciónEstado
Texto, foto, documento, encuestas✅ implementado
Edit / delete / pin / reacciones / forward✅ implementado
Teclados en línea + pulsaciones (callback_query)✅ implementado
Menú de comandos (setMyCommands)✅ implementado
getUpdates long-poll y webhooks✅ implementado
Respuestas citadas✅ implementado
Bots en grupos/canales (>2 participantes)⚠️ los métodos funcionan en un grupo donde el bot ya está; añadirlo a un grupo a través de la Bot API aún no está conectado
Modo en línea (@bot … en cualquier chat)❌ aún no compatible
Pagos en el bot❌ aún no compatible

Alojamiento

La mayoría de los bots no necesitan alojamiento: trabajas a través de la pasarela gestionada de Koto — basta con tu token kbot_… y la URL base pública.

¿Necesitas control total sobre las claves? La pasarela y un único conector (mantienes las claves del bot tú mismo, la misma API) se pueden desplegar por tu cuenta. Las opciones de despliegue y las variables de entorno se describen en el README del repositorio koto-bot — aquí, en la referencia pública de la API, no los duplicamos.

Descargar para Windows