Changelog · página 5 de 12

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 21 ago 2026 – 29 ago 2026. También puedes suscribirte al feed.

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ó.
v2.42.1 Nuevo

Los leads del sitio llegan directamente al CRM interno

El formulario de demostración de Meteor ya no depende del CRM externo heredado. Ahora registra cada solicitud directamente en el workspace autorizado mediante:

curl -X POST https://api.met.meteor.com.co/api/v1/contacts/web-leads \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Ana Pérez","phone":"+573001234567","email":"ana@example.com"}'

El endpoint requiere el scope contacts:write, deduplica por teléfono y conserva la trazabilidad del origen con las etiquetas s.a.p y website-demo.

v2.42.0 Nuevo

Los eventos quedan guardados 30 días, los escuche alguien o no

Hasta ahora un evento existía solo en el instante en que se emitía: si tu servidor estaba caído, o si todavía no habías creado el webhook, ese evento no volvía nunca. Por eso conectar algo crítico a los eventos era una apuesta.

Ahora todo evento queda guardado 30 días, haya o no un endpoint escuchándolo, y se puede consultar después:

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

Es el mismo sobre que se firma y se entrega por webhook, con el mismo id: si recibiste una entrega y quieres volver a leerla, pídela con ese id.

GET /events pagina por cursor como el resto de las listas: limit (hasta 100), starting_after con el id del último evento que viste, y has_more para saber si quedan más viejos. Con types filtras por tipo, separando con comas.

Solo ves los eventos cuyo permiso de lectura lleva tu clave: una clave sin billing:read no ve billing.threshold, aunque tenga events:read. Y una clave de prueba solo ve eventos de prueba. Ambos endpoints piden events:read.

v2.41.0 Mejora

Las Funciones IA pueden exigir validaciones previas

Las Funciones IA aceptan ahora required_tools, una lista de herramientas que deben terminar correctamente antes de ejecutar la función durante el turno actual.

El Met recibe el prerrequisito dentro de la descripción de la herramienta y el servidor también lo aplica. Si intenta ejecutar ambas herramientas en paralelo, o si la validación falla, la función dependiente no corre y devuelve un error reintentable required_tool_missing con la lista pendiente.

Esto permite proteger acciones transaccionales, por ejemplo exigir una consulta de inventario antes de registrar un pedido. Las funciones existentes conservan el comportamiento anterior porque required_tools es una lista vacía por defecto.

v2.40.0 Mejora

El límite por minuto sube a 300, y el 429 por fin trae el código que esta guía documenta

Dos cambios en el límite de requests por minuto. El segundo importa más que el primero.

El techo por defecto pasa de 100 a 300 por minuto

No hay que hacer nada: si tu key no tiene un límite propio asignado, ya tiene el nuevo. Las cabeceras X-RateLimit-* de cada respuesta reflejan el valor vigente, así que no hace falta que confíes en este número: míralo ahí.

El 300 sale de medir una semana de tráfico real, no de redondear hacia arriba. La integración más grande que tenemos nunca tocó el techo: su pico es de 32 requests por minuto. La que sí lo tocaba es un proceso por lotes que corre en ráfagas y pide unos 105 por minuto sostenidos mientras corre — perdía exactamente cinco por minuto contra un techo de 100. Su pico de llamadas atendidas fue 117. El nuevo valor es tres veces esa demanda real.

Si necesitas más de 300, no hace falta esperar a que cambiemos este número: se le puede asignar un límite propio a tu key.

El 429 ahora dice rate_limited

Esta guía siempre dijo que reintentes cuando el código sea rate_limited. El servidor respondía too_many_requests, con el mensaje ThrottlerException: Too Many Requests — el nombre de una clase interna, en inglés.

Si escribiste tu reintento siguiendo esta guía, esa rama de tu código nunca se ejecutó. Ahora sí:

{
  "success": false,
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Se superó el límite de requests por minuto de esta API key. Espera 12 segundos y reintenta (ver la cabecera Retry-After)."
  }
}

La cabecera Retry-After siempre estuvo ahí y sigue igual. Si usas nuestros SDK de TypeScript o Python no tienes que hacer nada: reintentan por el estado HTTP 429, no por el código del cuerpo, así que este cambio no los toca.

Si tu integración es a mano y llegaste a depender de too_many_requests —el valor que no estaba documentado— ese es el único caso que hay que ajustar.

Por qué esto importa más que el techo

En una sola ventana de un minuto vimos 894 rechazos contra una misma key. Eso no es demanda: es una integración que recibió un 429 y reintentó de inmediato, una y otra vez, construyendo su propia avalancha. Subir el techo no arregla ese patrón — solo mueve la pared. Lo que lo arregla es que el reintento con espera que ya escribiste, siguiendo esta guía, por fin se dispare.

v2.39.0 Mejora

El listado de contactos deja de cargar con dos campos de configuración interna

GET /contacts devolvía 573 KB por página de 100 contactos, y el 80,7% de ese peso eran dos claves que el listado no usa:

clave% de la respuesta
$followup_rules60,5%
$ad_referral20,2%

Las dos salen del listado. El detalle no cambia: GET /contacts/{id} las sigue devolviendo completas.

Por qué pesaban tanto

$followup_rules es la configuración de seguimientos que un flujo sincroniza en cada contacto para poder revalidarla cuando dispara. En el workspace que medimos, los 194 contactos tenían exactamente la misma versión — unos 3,5 KB repetidos fila por fila. Un listado de 100 contactos publicaba esa misma configuración cien veces.

$ad_referral es el texto completo del anuncio del que llegó el contacto. Útil al abrir la conversación; no al listar.

Qué vas a notar

La respuesta pesa alrededor de una quinta parte de lo que pesaba. En la medición contra la colección más grande, la consulta bajó de ~510-710 ms a ~265 ms, que es el piso de la red: el listado ya no depende del peso de cada contacto.

Si leías alguno de los dos desde el listado

Pídelos en el detalle. Un barrido que necesite $followup_rules de muchos contactos ahora hace una llamada por contacto — es más trabajo, y es deliberado: esa configuración es del flujo, no del contacto, y sacarla del listado es lo que lo vuelve rápido para todos los demás.

El resto de los campos no cambia. Los de identidad —$name, $phone, $email, $status, $tags— y todos tus campos personalizados siguen viajando igual.

De dónde salió esto

De medir el tráfico real de la API: GET /contacts era el segundo endpoint más usado de la plataforma y el más lento de los que se usan de verdad. Es el mismo criterio que ya se había aplicado en agosto a las respuestas de las herramientas del MCP, donde estas dos claves salieron por la misma razón.

v2.38.0 Mejora

La referencia de Partners deja de ser una lista de 37 filas

La API de Partners publica 37 operaciones y hasta hoy la referencia las mostraba casi todas al mismo nivel: GET /partner/clients y POST /partner/projects/{id}/milestones/{milestoneId}/complete una debajo de la otra, sin nada que dijera cuál era cuál.

Ahora quedan en siete grupos, cada uno con una línea que explica qué se puede hacer ahí y un enlace directo a su sección del portal:

GrupoOperacionesScope
Clientes1partner:clients:read
Comisiones1partner:commissions:read
Liquidaciones2partner:payouts:read
Oportunidades11partner:leads:*
Proyectos15partner:projects:*
Tickets6partner:support:*
MCP1mcp:use

Los grupos coinciden con los scopes

No es casualidad ni estética: lo que ves en un grupo es exactamente lo que una key de ese dominio puede hacer, ni más ni menos. Si tu key tiene partner:leads:*, el grupo «Oportunidades» es tu superficie completa.

Comisiones y Liquidaciones quedan separados aunque sumen tres operaciones entre los dos. Juntarlos por «son pocos» habría hecho que el grupo prometa algo que la key no alcanza.

El orden no es alfabético

Abre con las cuatro operaciones de solo lectura que contestan «¿cuánto llevo y de quién?» — es lo que se puede probar sin escribir nada. Después el pipeline, que son las 26 operaciones donde está toda la escritura. Después soporte. MCP cierra, porque es un endpoint JSON-RPC y no un recurso REST.

Y las dos referencias ahora se ven igual

El contrato de Met también declara sus grupos (x-tagGroups), así que la barra lateral se organiza igual en las dos referencias. Sus 27 grupos quedan repartidos en seis secciones: Empezar, Datos, CRM y canales, Automatización, Workspace y Partners.

Ninguna operación cambió de nombre, de ruta ni de forma. Si generas tu cliente del contrato, esto no te toca nada.