Paquetes publicados y sin publicar
@botmesh/tiktok está implementado y con tests, pero es privado: no está en
npm y su API puede cambiar. El estado de publicación, los dist-tags y cómo
instalar cada paquete están en Paquetes y versiones.
Elegir un canal
WhatsApp tiene varias opciones:@botmesh/baileys: vincula el bot como un dispositivo de WhatsApp Web (QR o código de emparejamiento) y abre su propio socket. Sin servidor público ni webhook, con grupos y encuestas, sin coste por mensaje. Es un cliente no oficial: automatizar una cuenta puede infringir los términos de WhatsApp y acabar en el bloqueo del número. Deja activado el rate limiter.@botmesh/meta: la WhatsApp Cloud API oficial. Botones, listas, plantillas y formularios con WhatsApp Flows nativos, sin riesgo de baneo. Necesita un webhook HTTPS público, no tiene grupos y los mensajes libres solo funcionan dentro de la ventana de atención de 24 horas.@botmesh/evolution/@botmesh/wppconnect: ya tienes desplegado un Evolution API o un WPPConnect Server. El bot habla con ese gateway por REST y recibe sus webhooks. Ambos gateways manejan WhatsApp Web, así que valen las mismas advertencias que con Baileys (no oficial, sin botones nativos fiables). Lo común (cliente REST, media, reconciliación LID/PN) vive en@botmesh/wa-gateway-kit, una dependencia pública de ambos; se instala el canal, no el kit (salvo que escribas un transporte para otro gateway).@botmesh/twilio/@botmesh/gupshup: envías WhatsApp a través de la cuenta de ese proveedor. Admiten plantillas; Twilio cubre además SMS/MMS con la misma clase.@botmesh/gohighlevel: el bot responde a los contactos del CRM HighLevel por el canal que usaron (SMS, WhatsApp, Email, Facebook, Instagram, Live chat…).
@botmesh/telegram (long polling por defecto, webhook
opcional), @botmesh/discord (socket del gateway), @botmesh/messenger e
@botmesh/instagram (webhooks de Meta), @botmesh/email (cada hilo de correo
es un chat) y @botmesh/tiktok (comentarios en tus propios videos y DMs).
Socket, polling o webhook
- Socket / polling (el provider abre la conexión): Baileys, Discord, Telegram en modo polling, Email (IMAP IDLE). No hay nada que exponer a internet.
- Webhook (
capabilities.pushIngress: true): Cloud API, Messenger, Instagram, Telegram en modo webhook, Evolution, WPPConnect, Twilio, HighLevel, Gupshup, TikTok. Tu servidor HTTP recibe el POST y le pasa el body crudo y las cabeceras aprovider.ingest(), que verifica la firma o el token y devuelve el status HTTP con el que responder.@botmesh/serverresuelve ese cableado (body crudo, límites de tamaño, timeouts, límite de concurrencia, endpoints de salud) paranode:http, Express, Fastify y Hono.
@botmesh/server (pnpm add @botmesh/server): una
ruta por provider, y el handshake GET y los POST firmados quedan resueltos:
ingest():
GET, Telegram no tiene ninguno, y los providers
cuya autenticación cubre la URL también la reciben (el
ingest(body, headers, url) asíncrono de WPPConnect,
ingestRequest({ url, body, headers }) en Twilio y Gupshup). ingest() no
espera a tus handlers, así que la plataforma recibe su respuesta enseguida.
El constructor de todo provider por webhook (Telegram, solo en modo webhook)
lanza un error si falta su credencial de webhook (app secret, auth token o token compartido), salvo que
pases allowUnsignedWebhooks: true, pensado solo para desarrollo local
aislado. HighLevel es la excepción: su clave pública de firma viene incluida.
Matriz de capacidades
Los valores salen de la declaracióncapabilities de cada provider. Una
función marcada “no” se degrada, no se rompe: los botones y las listas
pasan a un menú de texto numerado, ctx.edit envía un mensaje nuevo,
ctx.react resuelve { skipped: true } y ctx.typing no hace nada (ver
Mensajes y media).
Contenido. Lo que cada canal envía de forma nativa.
Entrada y presencia. Cómo llegan los eventos y qué indicadores de presencia funcionan.
- Enviar reacciones solo describe el envío. Varios providers reciben
igualmente reacciones como eventos
reaction(Messenger, Instagram, Gupshup, TikTok…). ctx.stream:borrador= vistas previas nativas en borrador y un mensaje final (chats privados de Telegram; ediciones en el resto),edición= un mensaje que se edita a medida que crece el texto,fragmentos= sin vista previa en vivo, mensajes del tamaño de una frase con indicador de escritura (streaming: 'none'). Ver Respuestas en streaming.- Formularios:
nativoenvíaflow().form()como un WhatsApp Flow;campo a campopregunta cada campo con mensajes de texto. textFormat(no es columna): el formato de texto que muestra el canal, para que quien genere Markdown, como@botmesh/ai, lo convierta.'whatsapp'(*negrita*,_cursiva_,~tachado~): Baileys, Cloud API, Evolution, WPPConnect, Gupshup.'plain'(sin formato): Telegram (se envía sinparse_mode), Messenger, Instagram, TikTok.'markdown': Discord. Sin declarar: Email. Los providers que sirven varios canales deciden por chat con el método opcionaltextFormatFor(chatId), que gana acapabilities.textFormaty llega a los handlers comoctx.textFormat: Twilio devuelve'whatsapp'en los chatswhatsapp:y'plain'en SMS; HighLevel sigue el canal de respuesta del contacto ('whatsapp'en WhatsApp,'plain'en SMS, Email, FB, IG, Live chat, GMB y custom).- Plantillas es el tipo de contenido
template: plantillas de la Cloud API, Content Templates de Twilio (ContentSid),templateIdde HighLevel, plantillas de Gupshup. El resto de providers lo rechaza conUnsupportedContentError. - Todos los providers salvo Baileys aceptan el tipo de contenido
native(ctx.sendNative('<id del provider>', payload)) como vía de escape a la API propia del canal, con un payload específico de cada provider. Baileys lo rechaza conUnsupportedContentError. Discord, Messenger, Instagram, Evolution, WPPConnect, Twilio, Gupshup, HighLevel, Email y TikTok también rechazan un payload dirigido a otro id de provider en lugar de enviarlo.
Contrato común de los canales
Las mismas reglas valen en todos los canales, así un bot se comporta igual donde corra. Quien escribe un provider las comprueba con los helpers de@botmesh/core/testing
(ver Testing).
- Los timestamps son milisegundos epoch.
ctx.timestamp,InboundMessage.timestamp,InboundInteraction.timestampyDeliveryStatus.timestampson ms epoch en todos los canales. Los transportes que informan segundos (WhatsApp, Telegram, la Cloud API) se multiplican por 1000; uno que no informa hora (Twilio) usa la hora de recepción, nunca0. Telegram no envía la hora de pulsación de un botón, así que un callback query lleva la hora de recepción. - El texto largo se divide. Cada canal declara su límite de texto y el core divide un
envío
textmás largo en varios mensajes (ver Mensajes;splitLongText: falselo desactiva). - Las operaciones no soportadas no existen. Una operación que el transporte no puede
hacer no se implementa: falta el método opcional (
typing,markRead,editMessage,deleteMessage) y su flag de capacidad esfalse, así quectx.typing(),ctx.markRead()yctx.delete()no hacen nada. Un método que existe hace la operación o rechaza; nunca es un sustituto silencioso. - La presencia es de mejor esfuerzo sin conexión.
typing()ymarkRead()resuelven sin tocar el transporte mientras el último estado de conexión del provider no es'ready'(antes de questart()conecte, durante una reconexión, después destop()): sin error, sin cola y sin reintento posterior. El bot aplica la misma regla antes de llamarlos, registra la señal omitida en debug y la cuenta enmetrics().presenceSkipped(botmesh_presence_skipped_totalentoPrometheus()). Ya conectado, un fallo del transporte sigue rechazando.assertPresenceWhileDisconnected()lo comprueba en un provider. - Demasiadas opciones rechazan. Un transporte que muestra menos botones, filas o
respuestas de encuesta de las que enviaste rechaza con
UnsupportedContentError(Cloud API, Messenger, Instagram, Discord), salvo que tenga una degradación documentada (texto numerado en Baileys, Evolution, WPPConnect, Gupshup, TikTok). - Una ruta local de media que no se puede leer rechaza con
UnsupportedContentError(el error de fs comocause), nunca con unENOENTcrudo. - Las esperas tienen tope. Cada llamada REST tiene timeout (
requestTimeoutMsen la Cloud API, Telegram, Discord, Messenger e Instagram) y unRateLimitedErrornunca pide más de 24 h. - Una edición conserva el id original. Donde el transporte informa de ediciones de
texto (Baileys,
edited_messagede Telegram,MESSAGE_UPDATEde Discord), la edición llega como mensaje con el texto nuevo y elref.idoriginal; cada uno de esos paquetes exportaisEditedMessage(ctx)y una opcióneditedMessages: 'ignore'. El dedupe del core deja pasar la edición porque su contenido cambió y descarta una re-entrega de la misma edición. - Los votos de encuesta tienen una sola forma. Baileys y Telegram emiten cada voto
como evento
'poll'(bot.on('poll', (vote) => …)):vote.refes el mensaje de la encuesta,vote.senderIdquien votó yvote.optionsel recuento actual de cada opción con susvoters. - Un solo esquema de nombres para los helpers de bajo nivel. El mapeador de errores
de cada provider es
to<Canal>Error(toTelegramError,toDiscordError,toTwilioError…; los canales de Meta compartentoGraphErrorde@botmesh/graph-core). Telegram, TikTok y la Cloud API conservan su antiguotoProviderError(y Email sutoEmailProviderError) como alias deprecados; los canales que se publican por primera vez con la beta solo tienen los nombres nuevos.ingest()devuelve el estado HTTP con el que responder (unnumber); WPPConnect lo devuelve comoPromise<number>(resuelve los LID desconocidos contra el gateway antes de emitir, sin esperar a tus handlers) y elingest()de email recibe un mensaje crudo, no un webhook, y devuelve unEmailIngestResult.
Providers
Cada canal tiene su propia página con la configuración, las opciones y los límites.@botmesh/baileys
WhatsApp Web a través de Baileys: vinculación por QR o código, socket propio, grupos y encuestas. Ver Baileys (WhatsApp Web).
@botmesh/meta (WhatsApp Cloud API)
La WhatsApp Cloud API oficial: botones, listas, plantillas y formularios de WhatsApp Flows nativos sobre webhooks. Ver WhatsApp Cloud API.
@botmesh/telegram
Telegram Bot API, por long polling o webhook. Ver Telegram.
@botmesh/messenger
Facebook Messenger a través de la Send API de Graph y los webhooks de Meta. Ver Messenger.
@botmesh/instagram
DMs de Instagram de una cuenta profesional (Messenger API for Instagram). Ver Instagram.
@botmesh/discord
Gateway de Discord (WebSocket) para los eventos y REST para enviar. Ver Discord.
@botmesh/evolution
Evolution API v2, un gateway de WhatsApp self-hosted: REST de salida, webhook de la instancia de entrada. Ver Evolution API.
@botmesh/wppconnect
WPPConnect Server, un gateway de WhatsApp Web self-hosted: REST con token Bearer, webhooks con token en la URL. Ver WPPConnect.
@botmesh/twilio
Twilio Programmable Messaging: WhatsApp y SMS/MMS con una sola clase. Ver Twilio.
@botmesh/gohighlevel
HighLevel (LeadConnector) Conversations API: responde a los contactos del CRM por el canal que usaron. Ver HighLevel (GoHighLevel).
@botmesh/gupshup
Gupshup WhatsApp API, con callbacks autenticados por un token compartido. Ver Gupshup.
@botmesh/email
Email por IMAP IDLE y SMTP: cada hilo de correo es un chat. Ver Email.
@botmesh/tiktok (no está en npm)
TikTok API for Business: comentarios en tus propios vídeos y mensajes directos. Ver TikTok.
Actualizar desde una alpha de 2.0
Los bots nuevos pueden saltarse esta sección. Si tenías un bot sobre una de las primeras alphas de 2.0, el contrato común de los canales cambió algunos comportamientos; el detalle por paquete está en Notas de actualización: canales y plugins y Migrar a la API estable.Qué cambió en todos los canales
Qué cambió en todos los canales
ctx.timestampes milisegundos epoch en todas partes. Baileys, la Cloud API yMockProviderinformaban segundos epoch. Quita cualquier* 1000(new Date(ctx.timestamp)ya es correcto). Lo mismo vale para los timestamps deInboundMessage,InboundInteractionyDeliveryStatusen hooks propios. Un provider de terceros que aún emite segundos sigue funcionando: el core convierte un valor menor que1e12paractx.timestampy el log de mensajes, pero actualízalo para emitir ms (assertInboundContractlo detecta).- Las pulsaciones de botones en Telegram llevan la hora de recepción, no la fecha del mensaje que tiene el teclado.
- Se quitaron métodos que no hacían nada:
CloudAPIProvider#typing()y#deleteMessage(),TelegramProvider#markRead()yDiscordProvider#markRead(). Usactx.typing()/ctx.delete()/ctx.markRead()(que ahí no hacen nada) oprovider.typing?.(…). - El texto largo se divide en varios mensajes en vez de rechazar con
PayloadTooLargeError.new Bot({ splitLongText: false })recupera el comportamiento anterior. Los hooksbefore('send')siguen corriendo una vez por mensaje (sobre el texto completo, antes de dividirlo); losafter('send'), una vez por parte. - Demasiadas opciones rechazan en Discord (más de 25 botones u opciones de menú, más
de 10 respuestas de encuesta), Messenger (más de 3 botones, más de 10 filas de lista) e
Instagram (más de 13 quick replies) con
UnsupportedContentError; antes descartaban las opciones sobrantes en silencio. - Discord difiere las interacciones sin responder tras 2 s.
autoAcknowledgeMs: falserecupera el comportamiento anterior. Unctx.acknowledge('texto')tardío sale entonces como followup; sinappIdni id de aplicación recibido de Discord, rechaza. MockProviderinformacapabilities.typingyreadReceiptscomofalsesalvo que exista un métodotyping()/markRead()(antes tampoco tenían efecto), y emite timestamps en ms epoch.RateLimitedError.retryAfterMstiene un tope de 24 h.- Las encuestas de Telegram se envían no anónimas para que sus votos lleguen al bot
como eventos
'poll'.new TelegramProvider({ anonymousPolls: true })mantiene las encuestas anónimas. - Las ediciones de Discord se entregan como mensajes con el
ref.idoriginal; un handler que no deba verlas compruebaisEditedMessage(ctx)o usaeditedMessages: 'ignore'. - Helpers renombrados (los nombres antiguos son alias deprecados hasta v3):
pollTimeoutde Telegram (segundos) →pollTimeoutMs;toProviderError→toTelegramError,toTikTokError;toEmailProviderError→toEmailError; eltoProviderErrorde@botmesh/meta→toGraphErrorde@botmesh/graph-core. Discord, Messenger e Instagram quitaron sutoProviderErrorde las alphas antes de su primera publicación en npm: usatoDiscordError,toMessengerErrorytoInstagramError.
Siguientes pasos
- Mensajes y media: qué hace cada helper en cada transporte.
- Sandbox de plataformas: ejecuta un bot sobre los providers reales contra simuladores locales, sin cuentas.
- Servidor de webhooks: monta los providers por webhook
con
@botmesh/server. - Ventana de 24 h y costos: ventana de sesión de la Cloud API y seguimiento de uso.
- Formularios: WhatsApp Flows nativos en la Cloud API, campo a campo en el resto.