Una tarea que pide aprobación humana
Dejar que un Met haga el trabajo y se detenga a pedir permiso antes del paso que no se puede deshacer, con la decisión entrando desde tu propio sistema.
Hay pasos que no quieres automatizar del todo: aplicar un descuento, mandar un contrato, emitir una nota crédito. Una tarea puede hacer todo el trabajo previo y detenerse justo antes de ese paso, esperando a una persona.
Esta receta conecta esa pausa con tu propio sistema, para que la decisión se tome donde ya trabaja tu equipo en vez de en un panel más.
Antes de empezar
Tu key necesita tasks:read y tasks:write.
Las dos pausas, que no son la misma
| quién hace el trabajo | cómo se destraba | |
|---|---|---|
| Aprobación | el Met, y pide permiso para seguir | approveStep / rejectStep |
| Paso humano | la persona | completeHumanStep |
Confundirlas es el error más común: si el trabajo lo hizo el Met y tú llamas completeHumanStep, la ejecución avanza sin que nadie haya aprobado nada.
1. Dispara la tarea
import Met from '@meteor.ia/sdk';
const met = new Met(process.env.MET_API_KEY!, {
workspaceId: Number(process.env.MET_WORKSPACE_ID),
});
const ejecucion = await met.tasks.execute('tsk_123');
// → { id: 'tex_…', status: 'running', … }
2. Detecta que se detuvo y en qué paso
El detalle de la ejecución trae el resultado de cada paso de esa corrida en task_step_executions:
const estado = await met.tasks.execution(ejecucion.id);
const pendiente = estado.task_step_executions.find(
(p) => p.status === 'waiting_for_approval' || p.status === 'waiting_for_human',
);
if (pendiente) {
await avisarleATuEquipo({
ejecucion: ejecucion.id,
paso: pendiente.step_id, // ← el del paso, no el de su corrida
tipo: pendiente.status,
loQueHizoElMet: pendiente.output,
});
}
Un paso de ejecución pasa por pending, running, completed, failed, waiting_for_approval, waiting_for_human, approved y rejected.
Cada fila tiene dos identificadores:
ides el de esa corrida del paso ystep_ides el del paso dentro de la receta. Aprobar y rechazar piden elstep_id. Con el otro, la respuesta es un 404 que parece decir que el paso no existe.
Sondear está bien para empezar, pero para producción es mejor enterarse: suscríbete a task.completed con webhooks firmados y deja de preguntar.
3. Deja que tu equipo decida desde donde ya trabaja
const stepId = pendiente.step_id;
// Aprobar: la ejecución sigue al paso siguiente, de forma asíncrona.
await met.tasks.approveStep(ejecucion.id, stepId, 'Va, los montos cuadran');
// Rechazar: esa rama se detiene.
await met.tasks.rejectStep(ejecucion.id, stepId, 'El descuento no está autorizado');
// Paso humano: lo hizo tu sistema, no el Met.
await met.tasks.completeHumanStep(ejecucion.id, stepId, 'Contrato firmado y archivado');
El comentario que mandas queda guardado en approval_comment del paso, junto con quién decidió y cuándo. Es lo que después explica una corrida rara sin tener que reconstruirla.
Las tres operan sobre el id de la ejecución, no el de la tarea. El paso pertenece a la receta, pero la pausa pertenece a la corrida: usar el id de la tarea es el error que más tiempo cuesta aquí.
4. Cortar una corrida
await met.tasks.cancelExecution(ejecucion.id);
Distinto de pausar la tarea con met.tasks.setStatus(tarea.id, 'paused'): eso impide que nazcan ejecuciones nuevas y no detiene las que están corriendo.
Lo que hay que decidir antes de poner esto en producción
Una ejecución detenida se queda detenida. Si nadie aprueba, ahí sigue — no hay tiempo límite que la resuelva por ti. Decide desde el principio qué pasa con una aprobación que nadie miró en 48 horas: recordar, escalar, o cancelar y rehacer. Es una decisión de producto, y la respuesta "ya la mirará alguien" termina siempre en la misma llamada de un cliente preguntando por algo que quedó a medias.
Y por lo mismo, una tarea con pausas humanas no va en CI: el job se queda esperando hasta el tiempo límite. Para lo desatendido, mira ejecutar un Met desde GitHub Actions.
Y después
- Pasos, disparadores y el modelo completo: Tareas.
- Enterarte del final sin sondear: Eventos en vivo.