Changelog · página 6 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 27 ago 2026 – 29 ago 2026. También puedes suscribirte al feed.

v2.47.0 Nuevo

Tu agente ya sabe dónde está parado, y encuentra datos sin adivinar

El servidor MCP pasa de 34 a 39 herramientas. La que más cambia el día a día es la primera del catálogo:

met_whoami responde en qué workspace está el agente, si su clave es de prueba y qué permisos trae. Y hace algo que faltaba: le muestra el catálogo completo, incluidas las herramientas que no puede usar, con el motivo de cada ausencia. Antes, una herramienta ausente y una inexistente eran indistinguibles para el agente, así que no tenía forma de saber que le faltaba un permiso ni cuál pedir.

met_search_items busca en tus datos sin conocer de antemano la colección, y pagina. Antes solo se podía recorrer la primera página de una colección conocida.

met_get_contact, met_update_contact y met_list_contact_fields cierran el ciclo del CRM: el agente puede releer la ficha completa de un contacto, guardar lo que averiguó hablando con esa persona, y consultar qué campos personalizados acepta tu cuenta en vez de adivinar los nombres.

Además, cuando una herramienta falla ahora te devuelve un error estructurado —con su código, no una frase suelta— y, en los casos donde reintentar no sirve, te dice qué hacer.

v2.47.0 Nuevo

Reenvía un evento, y cambia el secreto de tu webhook sin perder entregas

Tres cosas que le faltaban a los webhooks salientes.

Reenviar un evento que ya pasó. Si tu servidor estaba caído, o si arreglaste un error y quieres volver a procesar algo, ya no tienes que esperar a que vuelva a ocurrir:

curl -X POST https://api.met.meteor.com.co/api/v1/events/evt_01M106.../replay \
  -H "Authorization: Bearer $MET_API_KEY"

Crea entregas nuevas, no reescribe las viejas, y quedan marcadas como reenvío para que las distingas en la pantalla de entregas. Pide webhooks:manage.

Cambiar el secreto sin perder una sola entrega. Antes, rotar el secreto rompía tu verificación en el instante del cambio. Ahora hay una ventana de solapamiento —24 horas por defecto— durante la cual cada entrega viaja firmada con los dos secretos, el nuevo y el anterior:

X-Met-Signature: t=<ts>,v1=<con el nuevo>,v1=<con el anterior>

Así verifica tu servidor si ya guardaste el secreto nuevo, y también si todavía no. Actualiza tu SDK: las versiones que prueban una sola firma no sirven durante la ventana.

curl -X POST https://api.met.meteor.com.co/api/v1/webhook-endpoints/<id>/rotate-secret \
  -H "Authorization: Bearer $MET_API_KEY"

Si el secreto se te filtró, pide una ventana de 0: el anterior deja de valer de inmediato.

Apagado con aviso. Un endpoint que agota todas sus entregas tres veces seguidas, y lleva al menos 24 horas fallando, se apaga solo y te llega un aviso por correo diciendo por qué. Son las dos condiciones a la vez: una caída de una noche no apaga nada, y un fallo viejo aislado tampoco.

v2.47.0 Nuevo

Nueve eventos más, y una consola para verlos

El catálogo de eventos salientes pasa de 17 a 26. Casi todos ya ocurrían dentro del producto y no salían:

EventoCuándo dispara
automation.run.failedUna automatización falló al ejecutarse.
contact.message.sentSalió un mensaje hacia un contacto, lo haya escrito el Met o una persona.
contact.deletedSe borró un contacto.
broadcast.completedUna difusión terminó de enviarse.
call.missedUna llamada quedó sin contestar.
billing.energy.lowEl saldo de Energía cruzó hacia abajo el umbral bajo.
billing.energy.depletedEl saldo de Energía se agotó.
billing.energy.rechargedEntró una recarga de Energía.
billing.subscription.deactivatedLa suscripción del workspace quedó desactivada.

Los de Energía disparan en el cruce del umbral, no mientras el saldo esté bajo: si no, una cuenta con poco saldo te mandaría un evento por cada ejecución.

Si estás suscrito con el comodín * los vas a empezar a recibir sin hacer nada. Si prefieres enterarte antes de recibirlos, suscríbete a la lista explícita.

Y ahora los puedes ver. En el panel, Desarrolladores → Actividad → Eventos lista lo que genera tu cuenta —lo escuche alguien o no— con su contenido completo y su id, que es el mismo que viaja en la entrega firmada. Sirve para decidir a qué suscribirte antes de escribir una línea de código.

Una precisión sobre el modo de prueba

Un evento se marca como de prueba solo cuando lo disparó una clave de prueba. Lo que no nace de una clave —un mensaje de WhatsApp que entra, un contacto creado desde el panel, un cobro— se queda siempre en vivo, porque no hay un entorno que propagar. Antes esto no estaba dicho en ningún lado; ahora sí, y ya no hay emisores que hereden el valor por descuido.

v2.47.0 Corrección

Corregido: el cuerpo que recibe tu Función son los argumentos, sin sobre

Si registraste una Función IA de tipo HTTP siguiendo nuestra guía, es muy probable que tu handler esté roto. Lo sentimos: el error era nuestro y estaba publicado.

Qué prometíamos. La guía y el SDK decían que tu endpoint recibe un sobre con tres campos, y el ejemplo mostraba call.arguments:

res.json({ result: buscarPrecio(call.arguments) });   // ❌ nunca funcionó

Qué manda Meteor en realidad, y siempre mandó. El cuerpo son los argumentos, planos. Si tu Función declara un parámetro sku, lo que llega es:

{"sku":"A-1"}

No hay sobre, ni id, ni tool, ni un campo arguments que los envuelva. Así que call.arguments era undefined en cada llamada.

Qué cambiamos. Nada del cable: el formato que viaja sigue siendo exactamente el mismo, porque cambiarlo rompería a todas las Funciones que ya están vivas. Lo que corregimos es lo que estaba mal, que era la promesa: el tipo del SDK y la guía. Ahora el handler te devuelve los argumentos directamente:

const handle = met.tools.createHandler(process.env.FIRMA_PRECIOS);
app.post('/precios', (req, res) => {
  let args;
  try { args = handle(req.rawBody, req.headers['x-met-signature']); }
  catch { return res.status(400).end(); }
  res.json({ result: buscarPrecio(args.sku) });   // ✅
});

Qué tienes que hacer. Si tu código lee call.arguments, léelo directo del objeto que te devuelve createHandler. El tipo MetToolCall queda como nombre viejo de MetToolArguments y tu editor te lo va a marcar como obsoleto.

Un GET no lleva cuerpo: ahí los argumentos van en la URL.

v2.47.0 Nuevo

Cuatro lecturas que ya estaban pidiendo, ahora públicas

Miramos qué endpoints estaban intentando llamar con clave de API y recibiendo un rechazo. Cuatro de esos intentos eran razonables y ya no fallan.

GET /workspaces/{id}/channels (channels:read) — la lista de tus canales con su identificador. Cerraba un hueco incómodo: siete operaciones públicas de envío por WhatsApp piden un channelId, y no había forma pública de averiguarlo. Se enviaba a ciegas, o no se enviaba.

GET /channels/{id}/templates (channels:read) — las plantillas aprobadas de un canal de WhatsApp. send-template ya era pública y exige el nombre y el idioma exactos de una plantilla aprobada por Meta; ahora puedes listarlos. Se le piden a Meta en el momento, así que una plantilla recién aprobada aparece de inmediato.

GET /contacts/extraction-catalog (contacts:read) — qué campos puede extraer el análisis de conversaciones de tu cuenta y si está encendido. Sin esto, POST /contacts/{id}/extract devolvía claves que no había cómo interpretar.

GET /billing/automation-usage (billing:read) — tu consumo de automatizaciones contra el techo de tu plan.

Además, la lista de canales ya no incluye la clave de conexión del canal. No la usaba ninguna pantalla y no tenía por qué estar viajando.

v2.46.0 Cambio

Lo que el modo de prueba hace, y lo que nunca hizo

Si leíste nuestra documentación y entendiste que una key met_test_ te daba un entorno aparte, la documentación tuvo la culpa. No lo da, y nunca lo dio. La API no cambió; lo que cambió hoy es lo que decimos de ella.

Lo que una key de prueba sí hace, y sigue haciendo igual:

  • Los runs no debitan Energía y quedan marcados con livemode: false.
  • Hay un tope diario de runs de prueba por workspace. Al alcanzarlo, 429 con test_run_daily_cap — un código que hasta hoy no estaba en ninguna guía y ahora vive en Límites y cuotas.
  • Los siete scopes con efecto externo responden 403 test_mode_restricted: enviar por WhatsApp, ejecutar integraciones, reportar conversiones, provisionar y recargar cuentas, tocar el medio de pago de un partner e instalar plantillas. Vale igual por REST y por el servidor MCP, donde esas herramientas ni siquiera aparecen en el catálogo.

Y lo que no hace, dicho sin rodeos:

  • Corre contra la misma base y las mismas tablas que producción. No hay copia, ni espejo, ni reversión.
  • Escribe de verdad. Lo que está bloqueado es el efecto externo, no la escritura: una key de prueba con items:write o contacts:write crea registros que tu equipo ve en el panel, y nada los borra cuando la key vence.
  • No se puede recoger después. Solo los runs y los eventos llevan la marca livemode; lo demás que escribas queda indistinguible de tu producción, así que no hay forma de pedir "bórrame lo de prueba".

Qué hacer en su lugar: emite la key de prueba con scopes de lectura únicamente (más runs:execute si vas a ejecutar Mets) — lo que no tiene scope de escritura no escribe. Si necesitas escribir, hazlo en un workspace aparte creado para desarrollo, que puedes borrar entero.

Eventos: revisa esto si escuchas con una key de prueba

El filtro por livemode no cruza los dos mundos, pero hoy casi nada se emite como evento de prueba: solo run.completed y run.failed de un run que disparaste con esa key, billing.threshold de la key misma, y el ping de una entrega de prueba. Todo lo demás del catálogo —contact.*, task.completed, conversation.handoff, channel.run.*, app.*, snapshot.*, conversion.*— se emite siempre en vivo, así que una key met_test_ no lo recibe nunca, ni por stream() ni desde el registro.

Si montaste un handler contra esos tipos y lo probaste con una key met_test_, lo que viste no fue un handler que funciona: fue un stream vacío. Pruébalo con una key met_live_.

La clave de demostración del portal sí está aislada

La que te damos en la portada sin pedirte registro es otra cosa, y es lo que buscabas: de solo lectura, con los permisos fijados por el servidor y no por la petición, contra un negocio ficticio cuyo Met solo tiene herramientas de consulta, con su propio tope de Energía y 24 horas de vida. Para mirar la forma real de las respuestas antes de escribir nada, empieza por ahí.

v2.46.0 Cambio

Los leads web vuelven al contrato, ahora con tus propias etiquetas

POST /contacts/web-leads vuelve a ser parte de la API pública, y con tres campos nuevos, los tres opcionales: tags, summary y lead_source.

{
  "name": "Ana Ramírez",
  "phone": "+573001112233",
  "tags": ["landing-negro", "pauta-google"],
  "summary": "Pidió una cotización de 200 licencias.",
  "lead_source": "landing-negro"
}

Por qué había salido, y por qué vuelve

La versión 2.45.0 lo retiró del contrato, y el diagnóstico era correcto: el handler escribía siempre las mismas etiquetas (s.a.p, website-demo), el mismo origen y un resumen que decía «recibida desde meteor.com.co/demo». Llamado con la llave de otro workspace, te marcaba tus contactos con nuestras cosas.

Lo que estaba mal era el remedio, no el diagnóstico. Sacarlo del contrato no lo vuelve interno de forma inocua: el control de acceso hace *default-deny* contra las rutas no declaradas públicas, así que el endpoint dejó de responderle también al formulario de Meteor, que es quien lo usa.

Así que el arreglo va donde estaba el problema: los valores dejaron de ser fijos. Ahora los eliges tú, y los defaults son los de antes.

Lo que no cambia

Nada, si no mandas los campos nuevos. Los defaults son exactamente los valores que el endpoint escribía antes, así que una integración que ya lo llame sigue comportándose igual sin tocar una línea.

Detalles que conviene saber

  • La deduplicación es por teléfono. Si el contacto ya existía, se completa conservando lo que tenía y la respuesta trae created: false con su id. No es un alta: es un upsert.
  • tags reemplaza, no suma. Si mandas ["landing-negro"], el contacto queda con esa etiqueta y no también con s.a.p.
  • tags: [] es válido y distinto de omitir el campo: significa «sin etiquetas». Omitirlo significa «pon las de siempre».
  • Límites: hasta 10 etiquetas de 1 a 64 caracteres, summary hasta 500 y lead_source hasta 120.
  • Para crear contactos en general siguen estando POST /contacts (uno) y POST /contacts/import (hasta 500 por lote). Este endpoint es para la captura de un formulario web, donde el teléfono es la llave y el alta repetida es normal.
v2.45.0 Cambio

La captura de leads del sitio sale del contrato público

POST /contacts/web-leads deja de ser parte de la API pública. Estuvo publicado un día y ningún SDK llegó a exponerlo, así que no hay integración que se rompa.

El endpoint existe para que el sitio de Meteor escriba leads en el CRM interno de Meteor: el handler estampa etiquetas fijas (s.a.p, website-demo) y un origen propio. Llamado con una API key de otro workspace le marcaría los contactos con nuestras etiquetas internas — o sea que publicarlo era ofrecer algo que nadie de afuera podía usar bien.

Para crear contactos desde una integración siguen estando POST /contacts (uno) y POST /contacts/import (hasta 500 por lote, con etiquetas propias), que son la superficie pensada para eso.

v2.44.0 Nuevo

Etiquetar todo el lote al importar, y re-subir el archivo para re-etiquetar

POST /contacts/import acepta dos campos opcionales nuevos:

  • apply_tags (hasta 20 etiquetas): se aplican a todas las filas del lote, además de lo que traiga la columna tags de cada fila. El archivo del cliente casi nunca trae una columna de etiquetas, así que hasta ahora lo importado quedaba sin etiquetar y solo se podía arreglar contacto por contacto.
  • on_existing: qué hacer con un contacto que el archivo vuelve a traer. fill (por defecto, el comportamiento de siempre) rellena solo los campos vacíos; overwrite deja que el archivo reemplace lo guardado; skip no lo toca y crea únicamente los nuevos.

Las etiquetas ya no siguen la regla de "solo si está vacío": siempre se suman a las que el contacto ya tenía. Antes un contacto con una sola etiqueta nunca recibía las nuevas, así que re-subir el archivo no servía para re-etiquetar — que es justo para lo que se re-sube. Un import nunca quita una etiqueta: para eso están la ficha del contacto y las acciones masivas del listado.

Las etiquetas se deduplican ignorando mayúsculas, porque el catálogo del workspace ya trataba VIP y vip como una sola.

En la app, el modal de importar tiene ahora un bloque "Acciones para todo el lote" con el selector de etiquetas (las del workspace, o una nueva escrita a mano) y la política para los contactos que ya existen.

v2.43.0 Nuevo

Un paso nuevo puede entrar en el medio del checklist, no solo al final

POST /tasks/{taskId}/steps acepta un campo nuevo, after_step_id: el paso se crea justo debajo del paso que le indiques, y los que venían después corren una posición.

{
  "name": "Confirmar la dirección con el cliente",
  "type": "human_task",
  "after_step_id": "6a1f…"
}

Sin ese campo nada cambia: el paso sigue yendo al final y step_order se asigna solo. Es un campo opcional, así que las integraciones que ya crean pasos no necesitan tocar nada.

Por qué existe

Hasta ahora la única forma de meter un paso en el medio eran dos llamadas: crear el paso al final y después reordenar el checklist entero con POST /tasks/{taskId}/steps/reorder, mandando la lista completa de ids. Con diez pasos eso son diez ids que tienes que tener a mano —y volver a mandar— para insertar uno.

Es el mismo movimiento que hace la aplicación cuando escribes una subtarea y pulsas Enter parado en la segunda de diez: la que escribes queda de tercera, no de undécima.

Detalles que conviene saber

  • El after_step_id tiene que ser de un paso de la misma tarea. Si mandas uno que no existe —o que ya se borró mientras armabas la petición— el paso se crea igual, al final del checklist: preferimos no perderte el paso por una referencia vieja.
  • El step_order de los pasos siguientes cambia en la misma operación. Si tienes la lista cargada, vuelve a pedirla con GET /tasks/{taskId} en vez de asumir los números que tenías.
  • POST /tasks/{taskId}/steps/reorder sigue igual y sigue siendo lo indicado para mover pasos que ya existen.
v2.46.0 Mejora

Los nombres de las operaciones ya no se pueden mover sin avisarte

Si generas un cliente a partir de nuestro contrato —o si usas el SDK de TypeScript, que ahora saca sus tipos de ahí— hay un cambio nuestro que te rompía el código sin que ninguno de los dos se enterara: renombrar una operación, o moverla de una ruta a otra.

Desde hoy no puede pasar en silencio. Los nombres y las rutas de las 318 operaciones publicadas están congelados, y un guardián frena cualquier cambio que los mueva antes de que salga.

Retirar una operación sigue siendo posible, pero solo por el camino de siempre: primero se deprecia —te llega en las cabeceras Deprecation y Sunset, y aquí en el changelog—, conviven al menos seis meses, y recién después se va.

Esto no cambia nada de lo que ya escribiste. Es una promesa sobre lo que no te vamos a hacer.

v2.43.0 Mejora

El SDK de TypeScript ya dice qué devuelve cada método

Hasta ahora, 165 de los 319 métodos del SDK de TypeScript devolvían unknown. El editor no te autocompletaba nada y tenías que adivinar la forma de cada respuesta —o dispararla contra la API para mirarla— antes de escribir el código que la usa.

Ya no: todos los métodos declaran su tipo, y esos tipos se generan desde el contrato público, así que no pueden desincronizarse de lo que la API responde de verdad.

const pagina = await met.events.list({ limit: 50 });
//    ^ el editor ya sabe: { object, data: EventEnvelopeDto[], has_more }

for (const ev of pagina.data) {
  ev.type;     // autocompleta los tipos del catálogo
  ev.created;  // number
}

Los tipos viajan dentro del paquete. Si usas TypeScript no tienes que hacer nada: actualiza y el editor empieza a ayudarte.

Dos cosas más que entraron con esto:

  • POST /conversions y POST /conversions/web ahora documentan su respuesta. Eran las dos únicas operaciones públicas que no lo hacían, y justo ahí importa: la compuerta puede descartar tu conversión y responder con éxito igual. Ahora el campo decision está documentado y sabes si llegó a Meta o se quedó en el camino.
  • Algunos tipos escritos a mano estaban equivocados, no solo ausentes: había métodos declarados como lista que en realidad devuelven un objeto. Generarlos desde el contrato los corrigió.