Changelog · página 2 de 14

Novedades de la API

Cada cambio de la superficie pública queda registrado aquí, del más nuevo al más viejo. Esta página cubre del 29 sep 2026 – 7 oct 2026. También puedes suscribirte al feed.

v3.24.0 Seguridad

Ejecutar una integración nativa por API respeta su exposición declarada

POST /integrations/{key}/tools/{tool} (y met.integrations.execute) ya no ejecuta cualquier integración nativa activa en tu workspace. Ahora responde 403 tool_not_allowed cuando la integración no está habilitada para salir por API:

  • Las integraciones que gastan dinero real, como la pauta en Meta y Google Ads o crear envíos en Skydropx.
  • Las herramientas internas de la plataforma, como la búsqueda web. Para lo que hacen existen endpoints con su propio scope: ejecutarlas por aquí le daba a una llave con integrations:execute lo que sus demás scopes no le permitían.

Las herramientas internas que hoy sí se usan por esta vía (el manejo de colecciones y Mets, el constructor de flujos, el CRM y la agenda) siguen respondiendo mientras tienen su endpoint público. Antes de cerrarlas avisaremos con fecha.

Siguen funcionando igual tus servidores MCP propios (los que registras con POST /integrations), la generación de imágenes y los conectores de terceros con credenciales de tu workspace: Alegra, Siigo, Shopify, Siesa, TCC, Wompi, Mercado Libre, WooCommerce y el resto que ya se anunciaban por esta vía. Tus Mets no cambian: dentro de un Run usan todas las integraciones del workspace igual que antes.

v3.23.0 Cambio

El límite diario de peticiones frena al 100 %, avisa al 90 % y no frena el envío de WhatsApp

Hasta esta versión, el límite diario de peticiones del workspace solo avisaba al 100 % y frenaba al triple. Desde ahora:

  • Al 90 % tu workspace recibe un aviso, una vez por día. Es nuevo.
  • Al 100 % recibe el aviso de siempre y, desde ahí, la API responde 429 con code: "daily_request_limit_exceeded" y un Retry-After con los segundos que faltan para las 00:00 UTC. Antes ese 429 solo llegaba al triple del límite.
  • Enviar WhatsApp no se frena. Las peticiones que usan el scope channels:send (enviar un mensaje o una plantilla de WhatsApp, y las difusiones) siguen contando contra el límite, pero pasan aunque lo hayas alcanzado.

El código del error, su forma y las cabeceras X-Daily-Limit, X-Daily-Remaining y X-Daily-Reset no cambian. Lo que cambia es cuándo llega el 429: si tu integración hace tráfico por lotes, mira X-Daily-Remaining y frena antes de llegar a 0, o amplía el límite con el complemento «Peticiones de API».

GET /billing/limits ahora devuelve enforcement: "hard" para api_requests_daily (antes "soft"), y la descripción de soft en la especificación ya no habla del triple: avisa antes y, al llegar, frena solo una parte.

v3.22.0 Nuevo

Lee la configuración de un canal sin abrir el panel

GET /channels/{channelId}/config (scope channels:read) devuelve la configuración operativa de un canal: si está conectado, qué flujo lo atiende, el enrutamiento por contenido, los Mets asignados y cada línea (número de WhatsApp, Page de Facebook, cuenta de Instagram o casilla de correo) con su alias, si está activa y qué flujo la atiende de verdad. Ese último dato viene en effective_flow_id y effective_flow_source, con la misma precedencia que usa la entrada de mensajes: primero la línea, después su cuenta y al final el canal. Una línea inactiva sale con effective_flow_id: null y effective_flow_source: "inactive", porque lo que entra por ella no se atiende. En correo solo aparecen las casillas de la Bandeja. Si un canal tiene más de 200 líneas o cuentas, la lista viene cortada y lines_has_more o accounts_has_more vale true.

Es solo lectura: no crea ni repara nada, así que sirve para diagnosticar sin cambiar lo que estás revisando. Si el workspace nunca configuró el canal, responde configured: false. No devuelve credenciales: ni tokens, ni PIN, ni la ruta del webhook. Un flujo o un Met que ya no existe aparece con status: "not_found" o found: false, para que veas la referencia rota.

En el SDK es met.channels.getConfig(channelId). Un canal de otro workspace responde 404, igual que uno que no existe.

v3.21.0 Nuevo

Reglas de asignación en los grupos de agentes

Un grupo de agentes puede tener reglas de asignación: una lista ordenada de «si el campo del contacto … → asignar a esta persona». Cuando un chat del grupo necesita asesor (el Met lo transfiere a una persona, o un flujo lo mete al grupo sin responsable), gana la primera regla que coincide con los datos del contacto. Si ninguna coincide, o la persona ya no está activa, sigue el reparto de siempre.

  • PUT /agent-groups/{id}/assignment-rules reemplaza la lista completa ({ "rules": [...] }). Una lista vacía borra las reglas. Cada persona de una regla tiene que ser miembro del grupo.
  • Cada regla trae field (la clave del campo del contacto, por ejemplo $region o un campo personalizado), operator (in = es uno de, contains = contiene, member = el valor del campo nombra al asesor por nombre completo, correo o id), values y user_id (null con member).
  • GET /agent-groups y el resto de respuestas de grupos traen el campo nuevo assignment_rules. Los grupos que ya existían lo traen vacío.

La comparación no distingue mayúsculas ni tildes: «Cúcuta» y «cucuta» coinciden.

v3.20.0 Nuevo

Elegir desde qué línea de WhatsApp sale una plantilla

POST /channels/{channelId}/whatsapp/send-template acepta el campo opcional sender_line_id: el phone_number_id de Meta de la línea desde la que quieres enviar. Sirve cuando el workspace tiene varias líneas conectadas y un tipo de mensaje tiene que salir siempre por la misma, por ejemplo los códigos de verificación por la línea de autenticación mientras la conversación comercial sigue por la suya.

La línea tiene que ser del workspace y estar activa. Si no lo es, el envío responde 400 con error igual a wa_sender_line_not_found o wa_sender_line_inactive, y no se envía nada desde otro número. La plantilla tiene que estar aprobada en la cuenta de WhatsApp (WABA) de esa línea.

El endpoint nuevo GET /channels/{channelId}/whatsapp/lines (scope channels:read) lista las líneas del canal con su sender_line_id, su número, su alias, su cuenta, si puede enviar (can_send) y cuál es la línea por defecto (is_default). No incluye credenciales.

Sin sender_line_id, la plantilla sale por la última línea a la que escribió el contacto. Antes esta ruta usaba la primera línea por la que había escrito, así que con varias líneas podía responder desde un número que la persona ya no usaba. A un contacto que nunca escribió se le envía desde la línea por defecto, igual que antes.

v3.19.0 Nuevo

Contactos acepta el chip rápido de la bandeja y cuenta cada chip

GET /contacts y GET /contacts/counts aceptan el parámetro opcional quick con uno de estos valores: open (conversaciones no cerradas, es decir, con estado distinto de finished y archived; sin estado cuentan como abiertas), unread, human o autopilot. Si envías status junto con quick=open, manda status; con quick=human, manda quick.

La respuesta de GET /contacts/counts trae el objeto nuevo quick con los números all, open, unread, human y autopilot. Cada uno se calcula con la búsqueda y los filtros que envíes, pero sin el propio quick.

Los dos cambios son aditivos: si no envías quick, las respuestas son las de siempre y solo se agrega el campo nuevo.

v3.18.0 Seguridad

Las variables secretas ya no se devuelven en claro

Una variable marcada como secreta (is_encrypted: true, encrypted: true en el SDK) ahora es de solo escritura hacia afuera. Hasta hoy la marca no ocultaba nada: GET /variables devolvía el valor tal cual, y cualquier llave con variables:read leía los tokens de tus Funciones HTTP y el secreto con el que Meteor firma sus llamadas.

  • GET /variables, GET /variables/{id}, POST /variables y PUT /variables/{id} devuelven las secretas con value: null y un campo nuevo, has_value, que dice si hay un valor guardado.
  • POST /variables/resolve deja el token de una variable secreta sin reemplazar.
  • La herramienta met_list_variables del servidor MCP tampoco lo muestra.

Los flujos, los Mets y las Funciones IA la siguen leyendo por dentro: nada de lo que ya funciona deja de funcionar. Para cambiar el valor, envíalo con PUT; no hace falta leerlo antes.

Si guardaste un token en una variable sin marcarla como secreta, márcala: las que no lo están se devuelven igual que antes.

v3.17.1 Corrección

Quedarte sin Energía ya no bloquea la API (402 energy_depleted)

Un workspace sin Energía recibía 403 workspace_blocked («El workspace no tiene una suscripción activa») en todas las llamadas con API key, lecturas incluidas, aunque GET /billing/access respondiera blocked: false y la app siguiera funcionando. Quedarte sin Energía no es perder la suscripción, y ahora la API lo trata así:

  • Las lecturas y las operaciones que no consumen Energía responden normal.
  • Las que sí la consumen responden 402 con code: "energy_depleted" y no se ejecutan: POST /workspaces/{workspaceId}/runs, POST /workspaces/{workspaceId}/images/generate, /images/edit, /images/video, POST /contacts/{id}/extract y POST /contacts/{id}/enrich. La especificación documenta ese 402 en cada una. Se resuelve recargando Energía; reintentar antes no cambia nada.
  • 403 workspace_blocked queda para la cuenta bloqueada (plan inactivo o vencido, prueba terminada, tope de contactos…), con el mismo criterio que GET /billing/access (blocked: true). Su message ahora dice el motivo concreto.

En los SDK, el 402 llega como MetInvalidRequestError con code === 'energy_depleted' y no se reintenta solo. Por el servidor MCP, la tool recibe el mismo código con la pista de avisarle a la persona en vez de reintentar.

Guía: Errores, idempotencia y paginación.

v3.17.0 Nuevo

Cada contacto trae el enlace a su conversación (app_url)

Los contactos traen un campo nuevo, app_url: el enlace que abre la conversación del contacto en Meteor. Sirve para guardarlo en la ficha del cliente de tu CRM y llegar al chat con un clic.

  • GET /contacts, GET /contacts/{contactId} y POST /contacts lo devuelven.
  • Los eventos que hablan de un contacto lo llevan en data: contact.created, contact.updated, contact.message.received, contact.message.sent, contact.message.failed, conversation.handoff y call.missed. contact.deleted no lo lleva.
  • En los flujos está disponible como $contact.app_url.

El enlace es estable: lleva el id del workspace y el del contacto, no el nombre del workspace, así que sigue funcionando si el workspace cambia de nombre. Abrirlo pide una sesión en Meteor con acceso a ese contacto.

Receta: Enlace a la conversación desde tu CRM.

v3.16.2 Corrección

Los patrones de validación de la especificación se publican sin barras

Algunos campos de la especificación declaraban su pattern con las barras de una expresión literal de JavaScript (por ejemplo "/^[A-Za-z]{2}$/"). Un validador generado desde la especificación exigía esas barras y rechazaba valores correctos como CO. Ahora cada pattern es solo la expresión ("^[A-Za-z]{2}$").

Campos corregidos en la especificación pública:

  • country y owner_phone al aprovisionar un workspace.
  • recurrence_time al crear o editar una difusión.
  • slug al actualizar el slug.

En la especificación de Partners se corrigieron los campos equivalentes del aprovisionamiento de cuentas (country, owner_phone) y el token de la confirmación de correo, que ahora acepta hexadecimal en mayúsculas o minúsculas, igual que el servicio.

El comportamiento del servicio no cambia: valida exactamente lo mismo que antes.

v3.16.1 Corrección

La especificación incluye el filtro de conversaciones sin respuesta

La especificación pública de Contactos documenta ahora el parámetro opcional unanswered tanto en GET /contacts como en GET /contacts/counts. El comportamiento del servicio no cambia: el filtro ya estaba disponible.

También se sincronizó la versión publicada de la especificación de Partners con el changelog vigente. No cambian rutas, permisos ni respuestas de Partners.

v3.16.0 Cambio

Reconocimiento de clientes LyP sin confirmaciones implícitas

La herramienta reconocer_cliente_actual ahora declara de forma explícita que reconocer al contacto no registra un pedido ni crea una cotización. Su respuesta incluye pedido_registrado: false y cotizacion_creada: false para que el asistente no confirme operaciones que todavía no existen.

Cuando el mensaje contiene un pedido explícito, el asistente debe continuar con cotizar_pedido_lyp y solo confirmar el registro si esa herramienta devuelve cotizacion_creada: true.

La selección de precios también prioriza la identificación autoritativa del Rutero antes del teléfono o el nombre. Así evita mezclar productos históricos de otro cliente sin desactivar el bloqueo de seguridad ante una contradicción real.