Changelog · página 6 de 9

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

v2.10.1

owner_kind admite METEOR, y se limpian dos schemas del contrato

Lo único que puede afectarte: owner_kind tiene un valor más.

En la Partners API, las tareas y los ítems de checklist de un proyecto declaran de quién es la responsabilidad del trabajo. Hasta hoy eran dos valores, PARTNER y CLIENT; ahora son tres:

owner_kind: "PARTNER" | "CLIENT" | "METEOR"

METEOR significa que el trabajo lo hace el equipo de Meteor. La situación existía y no existía la forma de decirla, así que se registraba como si fuera del partner.

Es un cambio aditivo: ninguna respuesta cambió de forma y los dos valores de siempre siguen significando lo mismo. Pero si tu código compara owner_kind contra una lista cerrada —un enum, un match exhaustivo, un switch sin rama por defecto— un valor nuevo puede hacerlo fallar. Conviene revisarlo antes de que te llegue el primer proyecto con tareas de Meteor. Si usas el SDK, actualízalo y el tipo ya lo trae.

Los enum cerrados son justamente la razón por la que esto se anuncia aunque del lado del servidor nada se haya roto: agregar un valor es compatible para quien lo emite y no siempre para quien lo lee.

Y dos schemas que salen de components, sin efecto para nadie:

  • SowItemDto — era el cuerpo de un endpoint interno de alcance de proyecto, que dejó de existir cuando el alcance y los hitos se unificaron en una sola lista. Nunca formó parte de una operación pública.
  • WhatsappWabaTargetDto — estaba declarado sin una sola propiedad y sin ninguna operación que lo usara. Era un artefacto de generación, no un contrato.

El conteo de operaciones —333 entre las dos superficies— no se movió.

v2.10.0

Los errores quedan documentados en el contrato, y el portal se puede usar

Hasta hoy el spec público describía 297 operaciones sin decir qué pasa cuando alguna falla: ni una sola respuesta de error documentada. Un dev tenía dos salidas, y las dos malas: llamar a ciegas contra producción, o leer los tipos del SDK en GitHub. Eso se cierra.

El catálogo de errores está en el contrato. Cada operación pública declara ahora sus respuestas 400, 401, 429 y 500, con el schema del cuerpo y un ejemplo real. La taxonomía es la de siempre —cinco type en lista cerrada, code en inglés, message en español— pero ahora la referencia interactiva la muestra en cada endpoint, en vez de esconderla en una guía.

  • error.typeauthentication_error, invalid_request_error, rate_limit_error, agent_error, api_error. El SDK los mapea 1:1 a clases de excepción.
  • error.code — específico y creciente: invalid_api_key, missing_scope, quota_exceeded, test_mode_restricted
  • request_idguárdalo. Es buscable en tu Workbench y es lo primero que pide soporte.

Vale igual para la Partners API: el catálogo vive en un solo lugar, así que las dos superficies no pueden divergir.

La referencia ya puede ejecutar requests. Con el botón *Test Request* pegas tu key y pruebas cualquier endpoint sin salir del portal. Usa una key met_test_ mientras exploras.

Buscador. ⌘K (o /) en cualquier página del portal: busca en las guías, en sus secciones, en las 333 operaciones de los dos specs y en el changelog.

Dos guías nuevas:

  • Skills — 20 operaciones que no tenían ni una línea de narrativa. Activar del catálogo, guardar credenciales, probar antes de vincular, y por qué activar una skill no se la da a todos tus Mets.
  • CLI (met) — el CLI existía, estaba publicado en npm y no tenía página. Incluye met listen --forward, que reenvía los eventos de tu workspace a tu servidor local para desarrollar webhooks sin túneles.

El servidor MCP deja de prometer lo que no tiene. La tabla de capacidades de MCP se genera del catálogo real: son 14 tools sobre 6 dominios. La tabla anterior estaba escrita a mano y listaba ocho dominios, cuatro de ellos sin una sola tool — y como el catálogo se filtra por los scopes de tu key, una tool que no existe se veía igual que un permiso faltante.

Y varias cosas que estaban rotas a la vista: las guías mostraban el título dos veces, el menú lateral no tenía índice de secciones, en el teléfono había que scrollear toda la navegación antes de llegar al texto, y compartir un link del portal no generaba preview. El changelog ahora tiene feed Atom.

v1.5.0

Exporta e importa flujos como JSON ("Flows as Code")

Un flujo de automatización ahora es un artefacto de texto portable: expórtalo a JSON, versiónalo en git, compártelo entre workspaces o genéralo por código. La definición del canvas viaja con sus referencias cruzadas (Mets, skills, MCPs, colecciones, canales, sub-flujos) reescritas como marcadores estables y descritas en un bloque dependencies — nunca datos vivos ni credenciales.

# Exporta un flujo
met api GET /workspaces/$WS/flows/$FLOW_ID/export > bienvenida.flow.json

# Previsualiza el import en otro workspace (no crea nada)
met api POST /workspaces/$WS2/flows/import/preview -d @<(jq '{doc: .}' bienvenida.flow.json)
  • GET /workspaces/:workspaceId/flows/:id/export (automations:read) — devuelve el documento portable { schema_version, kind, flow, dependencies, content_hash }. Se exporta lo publicado (o el borrador si nunca se publicó). Las referencias a datos vivos (contactos, ejecuciones) se anulan con aviso; se detectan posibles secretos pegados en texto libre.
  • POST /workspaces/:workspaceId/flows/import/preview (automations:read) — dry-run que no muta: valida el JSON, chequea tipos de nodo y resuelve cada dependencia contra el workspace destino (auto por nombre / código de sistema), reportando lo que quedó sin resolver.
  • POST /workspaces/:workspaceId/flows/import (flows:write) — crea el flujo como borrador desactivado. bindings permite mapear a mano las dependencias que no matchearon (o omitirlas); las que quedan sin resolver dejan la referencia vacía con aviso, sin romper la importación.
  • Importación idempotenteimport acepta target_flow_id: en vez de crear un duplicado, reescribe el borrador de ese flujo. Habilita el ciclo git-native (exportar → editar el JSON → reimportar sobre el mismo flujo). El preview informa existing_flow_id cuando ya hay un flujo con el mismo identificador, para elegir entre crear o actualizar.
  • Round-trip en el editor — "Copiar JSON" copia el subgrafo seleccionado (o todo el lienzo) al portapapeles; "Pegar JSON" lo fusiona en otro flujo del mismo workspace regenerando ids. Para cruzar workspaces se usa Exportar/Importar (que traduce las referencias a marcadores).

El formato reutiliza el motor de referencias de los Snapshots, así que un flujo exportado es honesto sobre lo que necesita para correr en otro lado.

v2.9.2

Un enlace nuevo para un adjunto, cuando lo necesites

Ahora que los adjuntos del hilo son privados, su enlace caduca a los 7 días. Eso está bien para leer el hilo —cada lectura trae enlaces recién emitidos— pero deja colgada a una integración que guarde referencias a documentos en su propio sistema: al octavo día, el enlace guardado no abre nada.

  • GET /partner/leads/:id/attachments/signed-url?storage_path=…
  • GET /partner/projects/:id/attachments/signed-url?storage_path=…
  • En el SDK: met.partner.leads.comments.signedUrl(leadId, storagePath) y su gemelo en proyectos, en TypeScript y en Python.

Devuelve el adjunto con un enlace recién firmado, más expires_in en segundos para que sepas cuánto te dura sin adivinarlo.

La regla, en una línea: guarda storage_path, no la URL. El storage_path no caduca nunca; la URL es de usar y tirar. Si ya guardaste URLs, no hace falta que migres nada — vuelve a pedirlas con el storage_path que viene en el mismo objeto.

Sin scope nuevo: monta el de lectura del objeto al que pertenece el hilo (partner:leads:read o partner:projects:read). Y el adjunto tiene que estar en ese hilo — un storage_path que no le pertenece devuelve 404, igual que uno que no existe.

v2.9.1

Los adjuntos del hilo dejan de ser públicos

Ayer, al anunciar el hilo de la relación, escribimos que los adjuntos quedaban en un bucket público y que no subieras por ahí nada que no pudieras compartir por link. Ya no es así: los archivos del hilo viven en un bucket privado y solo se entregan por URL firmada. Un GET sin credencial ya no abre nada.

Qué cambia para ti:

  • POST …/comments/upload ahora devuelve también bucket: es dónde quedó el objeto, y el servidor lo necesita para volver a firmar la URL cada vez que lees el hilo. Mándalo de vuelta en attachments, junto con el resto de la metadata, tal como lo recibiste.
  • La url que te devuelve el upload caduca. No la guardes como si fuera permanente: cada lectura del hilo trae una URL fresca. Lo que sí es estable es storage_path.
  • El campo type (siempre "file") ahora se acepta explícitamente. Si reenviabas la respuesta del upload completa, ya no te la rechaza.

Si hasta hoy armabas el objeto a mano con solo url y storage_path, sigue funcionando: bucket y type son opcionales, y los adjuntos que subiste antes se siguen leyendo.

v2.9.1

Paridad completa en los SDKs, y Tareas estrena guía

Auditamos las 297 operaciones públicas contra lo que realmente ofrecen los SDKs. Dos huecos, los dos cerrados:

  • met.variables.retrieve(id) — la única asimetría CRUD que quedaba: se podía listar, crear, actualizar y borrar una variable, pero no leer una sola por su id.
  • met.snapshots.submit(id) — enviar un snapshot propio a revisión editorial. El scope snapshots:publish existía en el contrato y no tenía superficie en ningún SDK: aparecía en la lista de scopes de tu key y no había forma de usarlo.

Con esto, TypeScript y Python cubren 297 de 297 operaciones, y ninguna ruta de los SDKs apunta a algo que no exista en el spec.

También estrena guía Tareas — 35 operaciones que hasta hoy solo existían en la referencia generada. Cubre el modelo (la tarea es la receta, la ejecución es el plato), los pasos, los disparadores, comentarios con adjuntos, vistas guardadas, y sobre todo las pausas para una persona: la diferencia entre aprobar un paso que el Met ya hizo y completar un paso que hiciste tú, y por qué las tres operaciones van contra el id de la ejecución y no el de la tarea.

Sabemos lo que falta y no lo escondemos: Skills (20 operaciones) sigue sin guía, y el CLI met cubre hoy run, runs, chat y listen — los dominios grandes (tareas, colecciones, contactos) todavía no tienen comando.

v2.9.0

Partners API — el hilo de la relación, con adjuntos

La conversación sobre una oportunidad y la de su proyecto son la misma. No es una decisión de la API: para Meteor, oportunidad, cliente y proyecto no son tres cosas sino la misma relación en tres momentos, y ahora la superficie pública lo refleja. Lo que escribiste mientras vendías sigue ahí cuando estás implementando — sin copiar nada, porque nada estaba en el lugar equivocado.

  • GET /partner/leads/:id/comments · GET /partner/projects/:id/comments — el hilo, del mensaje más viejo al más nuevo.
  • POST /partner/leads/:id/comments · POST /partner/projects/:id/comments — escribe un mensaje, con o sin adjuntos.
  • POST …/comments/upload — sube un archivo (multipart file) y devuelve su metadata para mandarla en attachments.
  • DELETE /partner/lead-comments/:id · DELETE /partner/project-comments/:id — borra un mensaje propio.
  • En el SDK: met.partner.leads.comments.* y met.partner.projects.comments.* (list · create · upload · delete), en TypeScript y en Python.

No hay scope nuevo. El hilo monta el de su dominio: leerlo pide partner:leads:read o partner:projects:read, escribirlo el :write correspondiente. Quien puede ver la oportunidad ve su conversación, y no antes — un scope aparte de "comentarios" habría dejado leer conversaciones de objetos que la key no puede ver.

Tres límites, dichos sin eufemismos:

  • Los adjuntos quedan en un bucket público: cualquiera con la URL abre el archivo, sin autenticación. No subas por ahí nada que no puedas compartir por link.
  • El tope por archivo es 25 MB (la superficie interna acepta más, pero ahí hay una sesión de por medio).
  • Las menciones no se pueden mandar por API: dependen de ids internos del equipo, y un id equivocado le notificaría a la persona equivocada. Salen en la lectura, como nombres.

También en esta versión: el SDK de Python alcanzó la paridad completa con el de TypeScript en met.partner — antes cubría seis rutas de solo lectura, ahora las 34 operaciones, incluidas escritura de oportunidades y proyectos, tareas, hitos, tickets y el hilo.

Todavía no: el hilo del cliente —el que no cuelga de una oportunidad ni de un proyecto— y los comandos de partner en el CLI met, que hoy opera sobre un workspace.

v2.8.0

Partners API — tickets de soporte

Soporte estrena superficie pública, y arranca por la API de partners: ya puedes abrir, responder y cerrar tickets desde tu propio portal.

  • GET /partner/tickets · GET /partner/tickets/:id (con el hilo de mensajes) · GET /partner/tickets/reasons, con el scope partner:support:read.
  • POST /partner/tickets · POST /partner/tickets/:id/messages · PATCH /partner/tickets/:id/status, con el scope partner:support:write.
  • En el SDK: met.partner.support.list/get/reasons/create/reply/updateStatus.

Con workspace_id el ticket se abre a nombre de un cliente de tu cartera y ese cliente lo ve en su Met; sin él es un ticket tuyo hacia Meteor. Es la pieza que te deja poner una mesa de ayuda de primer nivel en tu portal sin sacar al cliente de tu experiencia.

Estados: new · in_progress · waiting_client · resolved · closed.

Dos límites que la API respeta igual que el portal: las notas internas del equipo de Meteor nunca salen por esta superficie, y los tickets de prioridad crítica los gestiona solo Meteor.

Próximo: adjuntos y comentarios en oportunidades, proyectos y tickets.

v2.7.0

Partners API — escritura de oportunidades y proyectos

Si operas tu propio portal, ya puedes registrar y mover oportunidades y proyectos en Meteor desde ahí. Lo que creas por API es tuyo desde el primer momento: una oportunidad nace aceptada y a tu nombre, sin pasar por el pool de Meteor.

  • OportunidadesPOST /partner/leads, PATCH /partner/leads/:id, POST /partner/leads/:id/move, DELETE /partner/leads/:id y el detalle GET /partner/leads/:id, con el scope partner:leads:write. En el SDK: met.partner.leads.create/update/move/delete.
  • ProyectosPOST /partner/projects, PATCH /partner/projects/:id, POST /partner/projects/:id/advance-phase, tareas (/tasks, /project-tasks/:id), hitos y el detalle GET /partner/projects/:id, con el scope partner:projects:write. En el SDK: met.partner.projects.* y el sub-recurso met.partner.projects.tasks.
  • Idempotencia — los POST aceptan Idempotency-Key y el SDK genera uno por request: un reintento por timeout no te deja dos oportunidades iguales.
  • Etapas del pipeline: NUEVO · CONTACTADO · CALIFICADO · PROPUESTA · GANADO · PERDIDO.

Tres acciones se siguen gestionando solo desde el portal de Meteor, porque mueven dinero o atribución: proponer y aprobar el precio, asignar implementador, y convertir una oportunidad en cliente. advancePhase() las respeta — falla si el precio no está aprobado, si quedan hitos pendientes, o si el implementador no aceptó su oferta. Un proyecto creado por API es siempre de cliente.

Los dos scopes son exclusivos de keys de partner: una key de workspace que los pida recibe 403. Ya puedes marcarlos al crear una key desde Ajustes → Desarrolladores en tu portal.

Próximo: tickets de soporte (partner:support:*) y adjuntos y comentarios en oportunidades y proyectos.

v2.6.0

Imágenes, variables, visibilidad de colecciones y las tools de cada Met (SDK 0.5.0)

SDK @meteor.ia/sdk@0.5.0. Esta versión convierte en API de primera clase varias cosas que antes eran rodeos.

Generación de imágenes (met.images, scope integrations:execute, key live). Genera mockups sin resolver ids de integración a mano. Debita energía a tu workspace y devuelve una URL alojada por Meteor.

const img = await met.images.generate({ prompt: 'rótulo azul en fachada', aspect_ratio: '16:9' });
// img → { url, format, size_bytes, model, energy_debited }
await met.images.edit({ prompt: 'ponlo en acrílico', image_base64 });
await met.images.video({ prompt: 'giro 360', image_base64 });
  • POST /workspaces/{ws}/images/generate · /edit · /video.

Variables del workspace por API (met.variables.set/create/update/delete, scope variables:write). Guarda el token que tu Función HTTP resuelve con auth_workspace_variable — antes solo se podía desde el panel.

await met.variables.set('mi_api_token', '<TOKEN>', { encrypted: true });

Visibilidad de colecciones por Met (collections.expose_to_agent). Oculta una colección al LLM sin borrar los datos; aplica en todos los caminos (API, chat, canal).

await met.collections.update(collectionId, { expose_to_agent: false });

Las tools de un Met (met.agents.tools(agentId), scope agents:read). Descubre qué herramientas ve un Met y cuáles están deshabilitadas — el diagnóstico para saber por qué una Función no aflora, y qué nombres pasar a agents.update({ disabled_tools }).

const tools = await met.agents.tools(agentId);
// [{ name, source: 'collection'|'skill'|'function'|'internal', description, disabled }]
  • GET /workspaces/{ws}/agents/{agentId}/tools.

Bind de Met por conversación. En un Run, met (nombre o id) ejecuta ESE Met directo con sus Funciones. Con conversation_id, el primer met recibido queda fijado como default de la conversación: los runs siguientes que omitan met corren el mismo Met. Un met explícito siempre gana.

Errores de tool más claros. Cuando una Función HTTP falla, la respuesta indica la causa concreta (variable de auth ausente, 401 del endpoint, timeout) en vez de un error genérico. Nunca se exponen tokens ni secretos.

Mejoras de documentación del SDK: el handler HTTP directo de una Función quedó documentado como camino de primera clase (no necesitas un flujo para llamar a tu endpoint), y items.search aclara que es búsqueda por texto (léxica).

v2.5.0

Ejecuta un Met específico por Run, imágenes de entrada, y control fino de tools

Varias mejoras para construir el loop agéntico con precisión, pensadas con el feedback de los primeros integradores.

met en un Run ahora ejecuta ESE Met (bind, no hint). Antes el campo met era informativo y todo pasaba por el orquestador —que no cargaba las Funciones IA del Met—. Ahora, si pasas met (id o nombre), el Run ejecuta ese Met directamente con sus Funciones y tools:

const fn = await met.functions.create({ name: 'calcular_cotizacion', http: { url: '.../api/cotizar' } });
await met.functions.link(agentId, fn.id);

// Antes: la función no aparecía (el orquestador no la cargaba).
// Ahora: corre el Met "kami" con calcular_cotizacion disponible.
for await (const ev of met.runs.stream({ met: 'kami', input: 'Cotiza 3 piezas de acero' })) {
  console.log(ev.type, ev.data);
}

Si omites met (o no resuelve a un Met del workspace), el orquestador auto-rutea como antes. El metering es correcto en ambos casos (live cobra Energía, test es gratis).

Imágenes de entrada (visión). runs.create/stream acepta attachments para que el Met "vea" una imagen —clasificar una foto, leer un documento, validar un diseño—:

await met.runs.create({
  met: 'kami',
  input: '¿Este acabado coincide con el aprobado?',
  attachments: [{ url: 'https://.../foto-instalada.jpg', mime_type: 'image/jpeg' }],
});

Apaga tools por Met. met.agents.update({ disabled_tools }) desactiva tools nativas para un Met —por ejemplo, quitarle el acceso a las colecciones sin archivarlas—. Las tools deshabilitadas se ocultan del catálogo del modelo (ya no las ve ni las intenta) además de rechazarse en runtime:

await met.agents.update(agentId, {
  disabled_tools: [
    'mcp_meteor_list_collections', 'mcp_meteor_get_collection', 'mcp_meteor_list_items',
    'mcp_meteor_get_item', 'mcp_meteor_search_items', 'mcp_meteor_create_item',
    'mcp_meteor_update_item', 'mcp_meteor_set_item_name',
  ],
});

met.events — escucha el workspace en vivo. El SDK ahora expone el feed de eventos (met listen): una suscripción SSE efímera, sin montar un endpoint.

for await (const ev of met.events.stream({ types: ['contact.message.received', 'run.completed'] })) {
  console.log(ev.type, ev.data);
}

Más eventos que sí disparan. Se cablearon los emisores de contact.created, contact.updated, task.completed y conversation.handoff (antes estaban en el catálogo pero no llegaban). Suscríbete por webhook (met.webhooks.subscriptions) o escúchalos con met.events.stream.

v2.4.0

Construye el loop agéntico por SDK — Funciones que llaman tu endpoint, flujos y autopilot

El SDK 0.3.0 (npm i @meteor.ia/sdk@0.3.0) expone la superficie para armar todo el proceso agéntico desde tu backend, sin panel.

Funciones IA con handler HTTP directo. Una Función (una herramienta que tu Met puede llamar) ahora puede apuntar directo a tu endpoint HTTP — sin tener que armar un flujo:

const fn = await met.functions.create({
  name: 'lookup_price',
  description: 'Consulta un precio en el backend del cliente',
  parameters: [{ name: 'sku', description: 'Código de producto', required: true }],
  http: {
    url: 'https://tu-servidor.com/api/price',
    method: 'POST',
    sign_secret_variable: 'PRICE_SECRET', // firma cada request con X-Met-Signature
  },
});
await met.functions.link(agentId, fn.id);

Meteor llama tu endpoint con los argumentos que el Met recolectó (body JSON), lo firma con HMAC (X-Met-Signature) para que verifiques el origen con met.tools.createHandler, y devuelve tu respuesta al Met como resultado de la herramienta. Los secretos nunca se guardan en crudo: se referencian por nombre de variable del workspace (sign_secret_variable / auth_workspace_variable). También sigue disponible el handler por flujo (flow_id) con un nodo http.request, ahora creable por SDK con met.flows.*.

Nuevo en el SDK:

  • met.functions.* — crear/listar/actualizar/borrar Funciones IA + link/unlink a un Met (scopes functions:read/functions:write).
  • met.flows.* — crear un flujo, editar su lienzo (draft_definition), publicar, duplicar, archivar, ejecutar (flows:write / automations:*).
  • met.contacts.setAutopilot(id, enabled?) y pauseAutopilot(id, minutes) — prende/apaga o pausa el autopilot de un contacto para el handoff a un humano (scope handoff:manage).

Con esto el patrón completo es: crear el Met (met.agents.create), definir la Función que llama a tu API, vincularla, y —en canales— el Met responde solo cuando entra un mensaje.