En esta sección
Guías / Automatizaciones

Automatizaciones

El *cuándo* de tu workspace: conecta un evento con una acción y deja que Meteor la dispare sin que nadie llame a la API.

Actualizada el Ver .md

Una automatización une dos cosas: un trigger_type —el evento que la despierta— y un action_kind —lo que hace cuando eso pasa—. Es el *cuándo* del plano agéntico: Funciones y flujos pone la lógica, Tareas pone el procedimiento, y esto decide qué los enciende.

Usa los scopes automations:read, automations:write y, para disparar a mano, automations:execute.

El modelo en una frase

Un tipo del catálogo, unas condiciones y una acción. Nada más:

const auto = await met.automations.create({
  name: 'Publicar cuando el deal se gana',
  trigger_type: 'item.field_changed',
  conditions: { collection_id: 42, field: 'estado', to: 'ganado' },
  action_kind: 'flow',
  flow_id: 'f1e2d3c4-0000-4000-8000-123456789abc',
});

console.log(auto.id, auto.enabled);   // → '…', true
auto = met.automations.create(
    name="Publicar cuando el deal se gana",
    trigger_type="item.field_changed",
    conditions={"collection_id": 42, "field": "estado", "to": "ganado"},
    action_kind="flow",
    flow_id="f1e2d3c4-0000-4000-8000-123456789abc",
)

print(auto["id"], auto["enabled"])
curl -X POST https://api.met.meteor.com.co/api/v1/workspaces/7/automations \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Publicar cuando el deal se gana",
        "trigger_type": "item.field_changed",
        "conditions": { "collection_id": 42, "field": "estado", "to": "ganado" },
        "action_kind": "flow",
        "flow_id": "f1e2d3c4-0000-4000-8000-123456789abc"
      }'

Nace encendida salvo que mandes enabled: false. Los campos opcionales son description, icon, collection_id, action_config y enabled.

El catálogo manda

trigger_type no es texto libre: sale del catálogo. Léelo antes de construir nada, porque es también la lista de lo que puedes ofrecerle a tu usuario.

const catalogo = await met.automations.catalog();
catalogo = met.automations.catalog()
curl https://api.met.meteor.com.co/api/v1/trigger-catalog \
  -H "Authorization: Bearer $MET_API_KEY"

Cada entrada trae type (lo que va en trigger_type), category, label, description, icon, conditions_schema —qué hay que llenarle—, exposes —qué variables recibe la acción cuando se dispara— y enabled.

enabled: false no es un permiso que te falte. Son tipos publicados en el catálogo a los que el despachador todavía no reacciona. Se leen; crearlos responde 400. Filtra por enabled antes de pintar opciones en tu propia interfaz.

Los tipos que hoy disparan, con sus condiciones obligatorias:

trigger_typeSe dispara cuandoCondiciones obligatorias
item.createdEntra un ítem nuevo a una colección.collection_id
item.field_changedUn campo del ítem pasa a un valor concreto.collection_id, field, to
item.updatedEl ítem cambia, sin importar qué campo.collection_id
item.deletedSe borra un ítem de la colección.collection_id
contact.createdEntra un contacto al CRM (manual, por canal o por API).
contact.field_updatedCambia un campo del contacto.field, operator
date_timeLlega un instante exacto. Una sola vez.scheduled_date (ISO 8601)
recurrentToca el patrón cron.recurrence_pattern
field_datetimeUn tiempo antes, en, o después de un campo de fecha.source, field_id, direction
webhook.receivedLlega un POST a un webhook entrante tuyo.endpoint_slug
manualSolo a pedido. Ver la nota más abajo.

Al crear se verifica que las condiciones obligatorias estén presentes; el resto del objeto viaja tal cual y lo interpreta cada tipo. Si te falta una, la respuesta te dice cuál: Condición "collection_id" requerida para trigger_type "item.created".

recurrence_pattern acepta un cron de cinco partes (0 9 * * 1) o uno de estos alias: hourly (en punto, cada hora), daily (9:00), weekly (lunes 9:00) y monthly (día 1, 9:00). El patrón se evalúa en la zona horaria de tu workspace, y si no tiene una configurada, en hora de Colombia.

manual no tiene disparo por API. Se puede crear, pero run-now cubre únicamente procesos administrados y flujos recurrentes (más abajo). Si necesitas arrancar algo desde tu código cuando tú decidas, ejecuta el flujo directo con met.flows.run(flowId) o la tarea con met.tasks.execute(taskId).

Qué ejecuta: action_kind

action_kindQué haceQué le tienes que dar
taskEjecuta una tarea del workspace.task_id
flowEjecuta un flujo publicado.flow_id
ai_fieldRellena un campo de la colección con IA.collection_id y action_config.field

Si omites action_kind, se asume task — y entonces task_id pasa a ser obligatorio.

El flujo tiene que estar publicado. Conectar uno que solo tiene borrador responde 400: publícalo antes con met.flows.publish(flowId) — ver Funciones y flujos. La tarea o el flujo, además, tienen que ser de tu mismo workspace.

Leer, encender, apagar y borrar

const todas = await met.automations.list();
const deUnaTarea = await met.automations.list({ taskId: 'd4c3b2a1-…' });

const una = await met.automations.retrieve(auto.id);

await met.automations.setEnabled(auto.id, false);              // apagar
await met.automations.update(auto.id, { conditions: { collection_id: 42, field: 'estado', to: 'perdido' } });

await met.automations.remove(auto.id);
todas = met.automations.list()
de_una_tarea = met.automations.list(task_id="d4c3b2a1-…")

una = met.automations.retrieve(auto["id"])

met.automations.set_enabled(auto["id"], False)
met.automations.update(auto["id"], conditions={"collection_id": 42, "field": "estado", "to": "perdido"})

met.automations.remove(auto["id"])
curl https://api.met.meteor.com.co/api/v1/workspaces/7/automations \
  -H "Authorization: Bearer $MET_API_KEY"

curl -X PATCH https://api.met.meteor.com.co/api/v1/workspaces/7/automations/$AUTO_ID \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'

setEnabled() es un atajo de update(): manda solo enabled y no toca el resto de la configuración.

Dos cosas que el listado devuelve y conviene mirar antes de creer que algo no anda:

Cuando la pausa no la pusiste tú

Una automatización puede volver apagada sin que nadie la haya tocado. Pasa con las que ejecutan un flujo: si una sola se desboca y consume por sí misma el techo de corridas del día del workspace, Meteor pausa esa automatización y deja el motivo escrito.

const a = await met.automations.retrieve(id);
if (!a.enabled && a.paused_reason) {
  // la frenó el sistema; a.paused_reason dice por qué
}

paused_reason: null con enabled: false significa lo contrario: la apagó una persona. Volver a encenderla con enabled: true limpia el motivo y le da cuenta nueva.

Lo importante para tu integración: se pausa la automatización culpable, no el workspace. Las demás siguen corriendo.

Procesos administrados

Algunas filas del listado llegan con is_system_managed: true. Son procesos que publica y versiona Meteor —reportes, recordatorios, herramientas que un Met usa dentro de una conversación—: su definición no se edita por PATCH, y update() con cualquier campo que no sea enabled responde 400. Tampoco se borran.

A cambio, tienen una superficie propia. Antes de usarla, mira lo que la propia fila declara:

const p = await met.automations.retrieve(id);

p.is_system_managed;              // true
p.capabilities.editable_fields;   // ['schedule', 'flow']
p.capabilities.locked_fields;     // ['handler', 'tool_name', 'templates', 'recipients']
p.capabilities.can_restore;       // true
p.managed_revision;               // 2
p.manual_run;                     // ¿admite ejecución a pedido?
p.last_run;                       // la última corrida, ya resuelta

Los seis métodos que siguen son solo para estas filas. Sobre una automatización que creaste tú responden 400, y eso es el contrato, no un problema de tu key.

Historial de corridas

const corridas = await met.automations.runs(id, { limit: 50 });
// [{ id, source: 'scheduled' | 'manual', status, run_key, result, error_message, started_at, finished_at }, …]
corridas = met.automations.runs(automation_id, limit=50)
curl "https://api.met.meteor.com.co/api/v1/workspaces/7/automations/$AUTO_ID/runs?limit=50" \
  -H "Authorization: Bearer $MET_API_KEY"

De la más reciente hacia atrás. limit va entre 1 y 100; sin él, 20. run_key es la llave de la ocurrencia (por ejemplo 2026-08-14): es lo que hace que el horario no corra dos veces lo mismo.

Para el historial de un flujo tuyo, la ruta es otra: met.flows.listRuns(flowId).

Ejecutar a pedido

const { ok, already_processed, run } = await met.automations.runNow(id, {
  input: { periodo: '2026-08-14' },
});
res = met.automations.run_now(automation_id, input={"periodo": "2026-08-14"})
curl -X POST https://api.met.meteor.com.co/api/v1/workspaces/7/automations/$AUTO_ID/run-now \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":{"periodo":"2026-08-14"}}'

already_processed: true significa que esa ocurrencia ya estaba corrida y tu pedido no duplicó nada.

La respuesta tiene dos formas y confundirlas cuesta una tarde:

const flowRun = await met.flows.findRun(run.id);

Responde 400 si el proceso está pausado, si no admite ejecución a pedido (manual_run en false) o si es un flujo que no es recurrente.

Cambiar el horario

await met.automations.updateSchedule(id, '0 12 * * 1-6');   // 12:00, de lunes a sábado
met.automations.update_schedule(automation_id, "0 12 * * 1-6")
curl -X PATCH https://api.met.meteor.com.co/api/v1/workspaces/7/automations/$AUTO_ID/schedule \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recurrence_pattern":"0 12 * * 1-6"}'

El cron es acotado a propósito: cinco partes, con una hora fija y días de la semana. El día del mes y el mes tienen que ir en *; cualquier otra cosa responde 400. Y solo aplica si capabilities.editable_fields incluye schedule — un proceso que se activa por un evento no tiene horario que cambiar.

Editar sin pisar a nadie

const p = await met.automations.retrieve(id);

await met.automations.updateConfiguration(id, {
  expected_revision: p.managed_revision,
  recurrence_pattern: '0 7 * * 1-5',
  flow_id: null,                 // desconecta el flujo posterior
});
p = met.automations.retrieve(automation_id)

met.automations.update_configuration(
    automation_id,
    expected_revision=p["managed_revision"],
    recurrence_pattern="0 7 * * 1-5",
    flow_id=None,
)
curl -X PATCH https://api.met.meteor.com.co/api/v1/workspaces/7/automations/$AUTO_ID/configuration \
  -H "Authorization: Bearer $MET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"expected_revision":2,"recurrence_pattern":"0 7 * * 1-5","flow_id":null}'

expected_revision es la revisión que traía la fila cuando la leíste. Si alguien la cambió en el medio, la llamada falla con 409 en vez de pisar el cambio ajeno; en los SDK llega como MetInvalidRequestError con status 409. Relee el proceso y vuelve a intentar con la revisión nueva.

Manda al menos uno de los dos campos configurables: sin ninguno responde 400. flow_id: null es explícito y sí se envía — desconecta el flujo.

Deshacer y ver quién tocó qué

await met.automations.restoreConfiguration(id, { expected_revision: p.managed_revision });

const cambios = await met.automations.configurationHistory(id, { limit: 20 });
// [{ revision, operation: 'update' | 'restore', changed_by_user_id, before_config, after_config, created_at }, …]
met.automations.restore_configuration(automation_id, expected_revision=p["managed_revision"])

cambios = met.automations.configuration_history(automation_id, limit=20)

restoreConfiguration() devuelve el proceso a la configuración que publicó Meteor y solo aplica si capabilities.can_restore es true. El historial va de lo más reciente hacia atrás, con limit entre 1 y 100 (sin él, 20).

Programar una tarea: usa esta API, no la de la tarea

Existe una ruta anterior para colgarle un disparador a una tarea desde la tarea misma (POST /tasks/{taskId}/triggers). Sigue publicada por compatibilidad, pero lo que crea no queda atado a un workspace, así que no aparece en GET /workspaces/{workspaceId}/automations ni pasa por la validación del catálogo.

Para programar una tarea hoy, crea una automatización que apunte a ella:

await met.automations.create({
  name: 'Calificar leads cada lunes',
  trigger_type: 'recurrent',
  conditions: { recurrence_pattern: '0 9 * * 1' },
  action_kind: 'task',
  task_id: tarea.id,
});

Errores que vas a ver

RespuestaQué la causa
400 trigger_type "…" no existe en el catálogoEl tipo no está en GET /trigger-catalog.
400 …todavía no está habilitado en producciónEl tipo existe pero llegó con enabled: false.
400 Condición "…" requerida para trigger_type "…"Falta una condición obligatoria.
400 El flow no ha sido publicadoConectaste un flujo que solo tiene borrador.
400 La task no pertenece a este workspaceLa tarea o el flujo son de otro workspace.
400 Esta automatización no tiene historial administradoLlamaste a runs() sobre una automatización tuya.
400 Los procesos administrados solo permiten activar o pausarUn update() con campos que no son enabled sobre un proceso administrado.
409 La configuración cambió en otra sesiónTu expected_revision quedó viejo.

El resto —401 por key o workspace equivocado, 429 por límites— se comporta igual que en toda la API: ver Errores, idempotencia y paginación.