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

v2.37.0 Corrección

El contrato ya declara el sobre en el que viaja toda respuesta

Toda respuesta correcta de la API viaja dentro de un sobre: no llega el recurso pelado, llega envuelto en {"success": true, "data": …}. Siempre fue así. Lo que no era así es el contrato OpenAPI, que describía el recurso sin el sobre.

{ "success": true, "data": { "object": "identity", "livemode": true } }

La API no cambió. Ni un endpoint, ni un campo, ni un código de estado. Lo que cambió es el papel, que ahora dice lo que la API venía haciendo.

A quién le importa esto

Si usas los SDK oficiales de TypeScript o Python: a ti no. Te entregan el contenido de data y convierten el sobre de error en una excepción. No tienes que hacer nada.

Si generas tu cliente del contrato: regenéralo. El cliente que salía hasta hoy buscaba el recurso en la raíz de la respuesta; el que sale ahora lo busca en data, que es donde viaja. Con eso la forma cuadra con lo que la API responde.

Si ya habías parchado tu cliente generado a mano para leer .data, regenerar te va a devolver ese parche como redundante — bórralo.

Si llamas con curl o con un cliente propio: nada cambia, pero ahora la referencia te muestra la forma correcta en vez de la incompleta.

Lo que cambió, en números

334 de 353 operaciones públicas —298 de Met y 36 de la API de Partners— pasaron a declarar el sobre en sus respuestas 2xx. Las 19 restantes no lo llevan y tampoco lo declaran, que es lo correcto:

  • Seis envíos de WhatsApp (/channels/{id}/whatsapp/send-*) devuelven success en la raíz sin data. Su forma no cambió.
  • POST /mcp, en Met y en Partners, responde el sobre JSON-RPC que define la especificación de MCP, que es otro.
  • Las respuestas sin cuerpo JSON: los 204, el stream de eventos (text/event-stream) y la descarga de archivos.

La paginación va afuera de data

Una lista paginada pone pagination como hermana de data, no adentro:

{
  "success": true,
  "data": [ { "id": 9812 } ],
  "pagination": { "page": 1, "limit": 50, "total": 128, "pages": 3 }
}

Eso también era así antes y tampoco estaba declarado. Ahora sí.

Dónde leerlo

La guía de errores e idempotencia abre con una sección nueva sobre la forma de una respuesta, con el sobre de éxito y el de error uno al lado del otro.

v2.36.0 Corrección

La tabla de scopes decía menos de lo que la API aplica

La tabla de scopes de la guía de autenticación se mantenía a mano y se había quedado atrás del código. Ahora se genera del catálogo de scopes cruzado con el contrato OpenAPI, y hay un chequeo que falla si vuelve a separarse.

Lo que hay que revisar si usas keys de prueba

El párrafo de modo de prueba listaba cuatro scopes bloqueados. Son siete. Los tres que faltaban son justamente los que tienen efecto sobre dinero:

conversions:write        emite un evento real a Meta
workspaces:recharge      inicia un cobro real en Stripe
partner:billing:manage   deja una tarjeta en archivo

La API siempre los bloqueó —una key met_test_ recibe 403 con test_mode_restricted—, así que no cambió ningún comportamiento. Lo que estaba mal era la guía: decía que una llave de prueba llegaba a sitios a los que nunca llegó. Si diseñaste tu integración creyendo eso, revisa esa parte.

Seis scopes que la tabla no mencionaba

Faltaban conversions:read, conversions:write, rag:read, rag:write, workspaces:recharge y partner:billing:manage. Ya están, los 57.

La tabla ahora trae una columna Endpoints con cuántas operaciones piden cada scope, y distingue tres situaciones que antes se veían iguales:

  • Con endpoints: el número.
  • Sin endpoints pero con eventos detrás: conversions:read no lo pide ninguna operación REST, pero sin él no puedes suscribirte a conversion.sent ni a conversion.discarded. Antes la guía decía que no habilitaba nada.
  • Retirados del panel: rag:read, rag:write y sites:read ya no se ofrecen al emitir una key ni al registrar una app OAuth.

sites:read sale de la vitrina

Nunca tuvo endpoints detrás: marcarlo no habilitaba ninguna llamada. Deja de aparecer entre los scopes que puedes pedir.

Las keys que ya lo tengan guardado siguen funcionando igual. El scope sigue siendo válido y no invalida nada; simplemente no se ofrece de nuevo. Es el mismo criterio que se aplicó a rag:read y rag:write.

Guía nueva: Automatizaciones

Doce operaciones que estaban solo en la referencia ahora tienen narrativa: qué disparadores existen y qué condiciones exige cada uno, cómo se programa una recurrencia y en qué zona horaria corre, cómo se edita una automatización gestionada sin pisar un cambio ajeno (expected_revision), y por qué un run-now sobre un flujo devuelve un run que no aparece después en el listado.

Probar una habilidad ya no alcanza ítems ajenos

POST /workspaces/{id}/skills/{skillId}/test aceptaba cualquier identificador de ítem de la plataforma, y el nombre del ítem encontrado volvía dentro de la respuesta. Ahora la búsqueda queda acotada al catálogo de habilidades: un identificador que no sea de una habilidad responde «no existe», sin distinguir entre lo que no está y lo que no es tuyo.

v2.35.0 Nuevo

Ya puedes preguntar quién eres, y la lista de eventos dejó de ser prosa

Dos huecos del mismo tipo: cosas que la API sabía y no había forma de preguntarle. Ninguno cambia comportamiento existente.

GET /me — con qué identidad entra tu key

Antes no existía introspección. Para saber si una key servía había que llamar a algo real y deducir por el código de error: 401 la key está mal, 403 le falta el scope, 2xx anda. Eso responde "¿sirve?", nunca "¿quién soy?" — el workspace y el entorno salían de lo que tuvieras configurado de tu lado, no de lo que el servidor resolvió.

GET /api/v1/me
{
  "object": "identity",
  "livemode": true,
  "api_key": {
    "object": "api_key",
    "id": "key_01HXYZ",
    "owner_type": "workspace",
    "env": "live",
    "scopes": ["items:read", "runs:read"],
    "rate_limit_rpm": 120,
    "monthly_quota": null
  },
  "workspace": { "object": "workspace", "id": 7, "slug": "acme" },
  "partner": null
}

rate_limit_rpm y monthly_quota son los vigentes: el más estricto entre lo que dice tu key y lo que dice el plan del workspace. Es el número con el que te vas a encontrar en un 429, y descubrirlo a golpes es peor que leerlo.

El secreto de la key no sale, ni nada con qué reconstruirlo: ni prefijo, ni los últimos caracteres, ni la longitud. Lo único que la identifica es su id, el mismo que ves en el panel y el que queda en los registros de request — sirve para pegar en un ticket sin ser una credencial.

Hoy pide el scope runs:read. Es una limitación conocida y es la que menos quita: es exactamente el scope que había que probar antes para simular esto, así que ninguna key quedó con menos alcance del que ya tenía.

En los SDKs es met.me.retrieve(), en TypeScript y en Python.

met whoami dejó de adivinar

El comando ya no deduce: pregunta. Y como ahora el servidor le dice cuál es tu workspace, aparece un caso que antes era invisible — si tu configuración local apunta a un workspace y la key opera otro, te lo avisa en vez de imprimir el tuyo con un visto bueno. met whoami --save-workspace guarda el que resolvió el servidor.

Los 17 eventos de webhook, en el contrato

enabled_events documentaba su lista en un párrafo y validaba contra otra en el código. Ahora las dos salen de la misma constante: el catálogo de eventos es la fuente, el contrato publica el enum y el validador usa esos mismos valores. No pueden separarse.

Si generas tu cliente del contrato, enabled_events pasa a traer la lista cerrada de valores válidos —los 17 más *— en vez de un string libre.

v2.34.0 Cambio

El modelo de un Met se pide por tier, no por id

Al crear o actualizar un Met, el campo model ahora se documenta con los tres tiers y nada más:

PATCH /agents/{id}
{ "model": "brillante" }

Si hoy mandas un id de modelo, tu integración sigue funcionando. No hay 400 nuevo. Lo que cambia es qué queda guardado: un id se resuelve a su tier y el Met queda con el modelo vigente de ese tier, no con el que nombraste.

Por ejemplo, "claude-sonnet-4-5" deja un Met en el Brillante de hoy.

Por qué

Un id de modelo es nuestro, no tuyo. Fijar uno dejaba a ese Met afuera de cada mejora que hacemos —más barato, más rápido, mejor— en silencio y sin fecha de vencimiento. Nos pasó de verdad: dos Mets quedaron dos generaciones atrás mientras el resto de la flota avanzaba, y nadie se enteró hasta que fuimos a mirar.

Con el tier eliges cuánta cabeza quiere tu Met. Qué modelo la provee es problema nuestro, y es el tipo de problema que preferimos resolver sin pedirte que cambies código.

Qué hacer

Si guardas ids en tu configuración, cámbialos por agil, brillante o genio. La respuesta de un agente ya trae tier junto a model, así que puedes leer de ahí lo que necesites mostrar.

Los ids se seguirán aceptando durante la ventana de deprecación. Cuando cierre, avisaremos aquí antes de que empiecen a rechazarse.

v2.34.0 Corrección

Las credenciales salen de dos respuestas, y una lista deja de ser global

Dos endpoints de lectura estaban devolviendo credenciales guardadas, y uno de ellos devolvía además datos de workspaces que no eran el tuyo. Los dos quedaron acotados hoy, sin ciclo de deprecación: no se le da seis meses de aviso a una respuesta que nunca debió llevar ese campo.

GET /skills/all ahora es de tu workspace

Antes leía la tabla entera sin filtrar por workspace. Ahora devuelve solo las habilidades activas de la cuenta a la que pertenece tu API key, y ya no incluye el objeto credentials.

Si tu integración contaba las filas de esta respuesta, va a contar menos. Es el arreglo, no una regresión: las filas que faltan nunca fueron tuyas.

GET /mcps/active ya no trae los valores de las credenciales

La respuesta pasó de ser la fila cruda de configuración a una proyección explícita. Lo que sí sigue viajando es mcp_data.credentials_required —los nombres de las credenciales que cada conexión necesita, que es lo que se usa para pintar un formulario— y lo que deja de viajar son los valores.

Un scope de lectura como integrations:read no debería alcanzar un secreto, y alcanzaba.

Las habilidades del workspace tampoco las devuelven

Cinco respuestas del catálogo de habilidades venían trayendo el objeto credentials de cada configuración:

GET  /workspaces/{id}/marketplace/skills     ← dentro de workspace_config
GET  /workspaces/{id}/skills/active
POST /workspaces/{id}/skills/{skillId}/activate
POST /workspaces/{id}/skills/{skillId}/deactivate
PUT  /workspaces/{id}/skills/{skillId}/credentials

La primera es la que más incomoda: skills:read es un permiso de lectura y alcanzaba un secreto. La última hacía eco de lo que acabas de guardar, que tampoco hace falta — ya lo tienes tú, y la respuesta la ve todo lo que esté en el camino.

Aquí el contrato no cambia: WorkspaceSkillConfigDto nunca declaró ese campo. Lo que cambia es que ahora la respuesta se parece al contrato.

Los enlaces entre ítems validan a qué workspace pertenecen

GET /items/{itemId}/links, POST /items/{itemId}/links y DELETE /item-links/{linkId} ahora verifican que el ítem sea de tu workspace antes de responder. Un id ajeno devuelve 404, no 403: la API nunca confirma que exista algo que no puedes ver.

En el POST se validan los dos extremos del enlace. Es deliberado: la lectura embebe el ítem destino, así que un enlace apuntando fuera de tu workspace habría convertido cada lectura posterior en una fuga.

Si generas tu cliente del contrato

Los schemas ActiveSkillResponseDto y ActiveMcpResponseDto pasaron de abiertos a cerrados: declaran exactamente los campos que viajan. Si tu generador aceptaba propiedades extra en estos dos, ya no hay ninguna que aceptar.

v2.33.0 Nuevo

Devolverle una cuenta gestionada a tu cliente

Una cuenta que aprovisionaste y venías pagando ahora puede pasar a manos de tu cliente, sin que él pierda nada de lo que tiene adentro:

POST /workspaces/{id}/handover

Desde ese momento la licencia se le cobra a él, tú dejas de pagarla, y esa cuenta vuelve a generarte comisión — el descuento que la reemplazaba termina con el traspaso.

Tres cosas que conviene saber antes de llamarlo:

  • Tu cliente necesita su propio medio de pago guardado. Si no lo tiene, la llamada responde 409 y no cancela nada. Es a propósito: soltar la cuenta antes de que él pueda pagarla la dejaría sin servicio, y el que se queda sin Met es él, por algo que no pidió.
  • La energía que le cargaste se queda con la cuenta. Ya es servicio entregado; no se descuenta ni se devuelve.
  • Se puede reintentar sin miedo. Si la llamada se corta a mitad de camino, repetirla termina el traspaso en vez de crear una segunda suscripción.

Tu cliente también puede pedirlo desde su propia facturación, sin pasar por ti. No es un descuido: una cuenta gestionada sin salida propia sería una cuenta de la que él no puede irse.

v2.32.0 Nuevo

Cargar energía sin abrir un enlace de pago

POST /workspaces/{id}/recharge acepta off_session: true y cobra directo a tu medio de pago guardado, sin devolver un enlace que alguien tenga que abrir:

POST /workspaces/42/recharge
{ "amount_usd": 100, "off_session": true }

→ 200 { "object": "energy_charge", "status": "succeeded",
        "payment_intent_id": "pi_…", "acreditado": false }

acreditado viene en false a propósito, incluso cuando el cobro salió bien. El saldo lo acredita el webhook del pago, que es el único que sabe que el dinero entró de verdad; sumarlo en esta respuesta daría saldo por un cobro que todavía se puede revertir. Si necesitas confirmar, consulta el saldo de la cuenta unos segundos después.

Sin la bandera todo sigue igual: devuelve el enlace de pago de siempre, así que nada de lo que ya tengas escrito cambia. Y si pides off_session sin medio de pago guardado, responde 409 diciendo cuál es la salida.

v2.31.0 Nuevo

Pasar una cuenta aprovisionada a un plan, cobrado a tu medio de pago

Si aprovisionas cuentas para tus clientes, ahora puedes pasarlas de Tech Partner a un plan comercial y que la licencia se cobre a tu tarjeta:

POST /workspaces/{id}/subscription
{ "plan_slug": "estudio", "billing_cycle": "monthly" }

La respuesta trae el descuento aplicado, su duración y el nivel con el que se calculó.

El descuento reemplaza tu comisión, no se suma a ella. Es el espejo exacto de lo que habrías cobrado: el mismo porcentaje, durante el mismo tiempo. Si tienes una tasa negociada, se usa esa y no la de tu nivel. Por esas cuentas no vas a ver comisión, y en el ledger queda dicho por qué.

Dos cosas que conviene saber antes de llamarlo:

  • Necesitas un medio de pago guardado. Sin él responde 409: una suscripción sin con qué cobrarla nace impaga, y el que sufre ese estado es tu cliente, que no puede resolverlo porque la factura no es suya.
  • Una cuenta solo puede estar gestionada una vez. Un segundo intento responde 409 en vez de duplicar el descuento.

La energía sigue cobrándose al margen del plan del cliente, así que pasar una cuenta a un plan también le baja lo que consume — que suele ser la razón real para hacerlo.

v2.30.0 Nuevo

Un Tech Partner ya puede dejar su tarjeta en archivo

Si aprovisionas cuentas para tus clientes, ahora puedes guardar un medio de pago a tu nombre y dejar de abrir un enlace de cobro cada vez.

POST /partner/payment-method/setup
{ "success_url": "https://tu-panel.com/ok", "cancel_url": "https://tu-panel.com/no" }

→ 200 { "checkout_url": "https://checkout.stripe.com/…", "session_id": "cs_…" }

El enlace abre un Checkout en modo setup: no cobra nada, solo deja la tarjeta guardada. Por tu integración nunca pasa un dato de tarjeta.

Para saber qué hay guardado, GET /partner/payment-method responde la marca, los últimos cuatro dígitos, el vencimiento y si ya venció. Se lee de la fuente en cada llamada, así que si cambias la tarjeta el cambio se ve enseguida.

Los dos van con el scope nuevo partner:billing:manage, aparte de workspaces:provision a propósito: una key que le entregas a un integrador para que te cree cuentas no debería poder, con el mismo permiso, cambiar la tarjeta con la que pagas todo. Como cualquier scope que mueve dinero, no funciona en modo test.

v2.29.0 Nuevo

Seis recetas de punta a punta y la documentación servida en markdown

Seis recetas nuevas arman un caso completo, de la primera línea a producción, con el código listo para copiar: un agente que contesta WhatsApp con tu lógica en el medio, sincronizar un sistema externo con colecciones, recibir eventos firmados en tu backend, ejecutar un Met desde GitHub Actions, mostrar un run en vivo en tu UI y una tarea que pide aprobación humana. Cada una declara con qué se arma, qué partes de la API toca y qué scopes necesita tu key.

La documentación también se sirve en markdown, para cuando quien la lee es tu agente. Cambia .html por .md en cualquier guía, o pide Accept: text/markdown sobre la misma URL y recibes el texto sin la página alrededor. llms.txt trae el mapa del portal y llms-full.txt las guías completas concatenadas.

Cada guía muestra ahora cuándo se actualizó por última vez, se puede copiar entera como markdown desde su encabezado, y todos los bloques de código del portal tienen botón de copiar.

Nuevo

"meteor-api: un pack de skills para los agentes que escriben código"

El servidor MCP entrega las herramientas; lo que le faltaba a un agente que programa contra Meteor era el criterio de cuál usar, en qué orden y qué decide el servidor por él. meteor-api es ese criterio, empaquetado en seis sub-skills —Mets, CRM, tareas, datos, automatizaciones y plantillas— que se instalan en .agents/skills/ y sirven en cualquier cliente que lea esa carpeta:

curl -fsSL https://developers.meteor.com.co/skill-pack/install.sh | sh

El pack se arma del mismo catálogo de herramientas que expone el servidor MCP y de las guías publicadas, así que dice lo mismo que la referencia.

Se llama meteor-api y no skills para no confundirlo con las Skills del producto, que son otra cosa: capacidades que activas y vinculas a un Met.

Además, catorce herramientas del servidor MCP ahora explican lo que antes había que descubrir usándolas: qué límite tiene la respuesta, qué campos vienen recortados, cuál es la herramienta que sigue y cuándo una operación debita Energía.

v2.28.0 Mejora

Procesos administrados visibles y controlables desde Automatizaciones

La API pública de Automatizaciones ahora refleja los procesos administrados por el sistema junto con las tareas, flujos y campos de IA del workspace. Una integración puede distinguirlos mediante is_system_managed, consultar su última ejecución y, cuando el proceso lo permite, ejecutarlo manualmente, revisar su historial o ajustar su horario seguro.

Los nuevos controles conservan los scopes granulares de Automatizaciones y no permiten editar la lógica interna del proceso administrado.