# Aprobaciones humanas

Hay acciones que un Met no hace solo. Cuando pide **publicar en redes, cobrar, emitir una
factura, gastar pauta, enviar una plantilla que Meta cobra o borrar algo**, la acción no se
ejecuta: queda como una **aprobación** esperando a una persona del negocio. Esa persona la
aprueba o la rechaza en Met —en la tarjeta del chat, en el Inicio o por WhatsApp— y recién
entonces se hace.

Con la API **ves** esas aprobaciones: qué se pidió, quién la decidió y qué salió. **No las
decides.** Aprobar algo que cobra o publica es de una persona, nunca de una key.

## Antes de empezar

Tu key necesita `approvals:read`. Las keys emitidas antes de que existiera este scope no lo
traen: agrégalo en **Ajustes › Desarrolladores** o emite una nueva. Funciona también con una
key de test (`met_test_`), porque solo lee.

## Un Run que quedó esperando

Cuando un Run pide una de esas acciones, el Met responde algo como «queda pendiente de tu
aprobación» y el Run termina en `completed`. La respuesta te dice que la acción no se hizo:

```ts
import Met from '@meteor.ia/sdk';

const met = new Met(process.env.METEOR_API_KEY!);
const run = await met.runs.create({ input: 'Publica en Facebook el post de la promo de otoño' });

if (run.awaiting_approval) {
  for (const a of run.approvals ?? []) {
    console.log(`Espera aprobación: ${a.action} (${a.approval_id})`);
  }
}
```

| Campo del Run | Qué es |
|---|---|
| `awaiting_approval` | `true` si dejó al menos una acción esperando. |
| `approvals[]` | Cada acción con su `approval_id`, `action`, `status` y `requested_at`. |

Al crear el Run, `status` es el de ese momento. En `GET /runs/{id}` (`runs.retrieve`) es el de
ahora: si alguien ya la aprobó, lo ves ahí. El evento `run.completed` lleva los mismos dos
campos cuando hay aprobaciones.

Si un Run vuelve a pedir algo que ya estaba esperando (un reintento tuyo, o el Met que insiste),
no nace una aprobación nueva: la que ya existía sigue siendo del Run que la pidió primero, y el
Run nuevo no la lista. Para ver todo lo que espera, sin importar qué Run lo pidió:
`approvals.list({ status: 'pending' })`.

## Leer las aprobaciones

```ts
// Lo que espera a una persona ahora mismo
const { data } = await met.approvals.list({ status: 'pending' });

// Todo lo que dejó un Run
const delRun = await met.approvals.list({ run_id: run.id });

// Una sola, con todo su detalle
const a = await met.approvals.retrieve(run.approvals![0].approval_id);
console.log(a.status, a.decided_by?.name, a.result?.text);
```

```bash
curl "https://api.met.meteor.com.co/api/v1/workspaces/$WS/approvals?status=pending,approved" \
  -H "Authorization: Bearer $METEOR_API_KEY"
```

Filtros de `GET /workspaces/{workspaceId}/approvals`:

| Parámetro | Para qué |
|---|---|
| `status` | Uno o varios, separados por coma: `pending`, `approved`, `rejected`, `executed`, `failed`. |
| `run_id` | Las que dejó un Run de la API. |
| `conversation_id` | Las que se pidieron en una conversación (sus 100 vueltas más recientes). |
| `since` / `until` | Por fecha de pedido, ISO 8601 con hora y zona. `since` se incluye, `until` no. |
| `limit` / `starting_after` | Paginación: 1–100 por página; pasa el `next_cursor` tal cual llegó. |

La lista va de la más nueva a la más vieja y responde `{ data, has_more, next_cursor }`. Para
recorrerla entera, `met.approvals.iterate({ ... })`.

## Los estados

| `status` | Qué pasó |
|---|---|
| `pending` | Espera a una persona. |
| `approved` | Una persona la aprobó y se está ejecutando (un video puede tardar minutos). |
| `executed` | Se ejecutó. `result` dice qué salió, con las piezas que produjo. |
| `failed` | Se aprobó, pero falló al ejecutarse. `result.error_code` dice por qué: `execution_failed` (la herramienta respondió con un error) o `interrupted` (se cortó antes de terminar). El detalle del error lo ve el negocio en Met. |
| `rejected` | No se hizo. `rejection_reason` distingue `rejected`, `changes_requested` (pidieron un cambio: está en `change_request`) y `replaced` (el Met pidió una versión más nueva: está en `replaced_by`). |

## Qué trae cada aprobación

| Campo | Qué es |
|---|---|
| `action` | Qué acción es, en palabras: «Publicar una imagen en Instagram», «Crear una factura en Siigo». |
| `summary`, `details` | Sobre qué: los datos para decidir, legibles («vertical 9:16», «Monto: 120000»). Sin correos, teléfonos ni documentos de tus clientes. |
| `draft` | Lo que redactó el Met (el texto o la instrucción de la pieza). |
| `preview` | El texto y las imágenes que se publicarían, y el presupuesto de pauta si gasta. |
| `met` | Qué Met la pidió (`id: null` es el Met principal). |
| `origin` | Dónde nació: `api_run`, `routine`, `channel` o `panel`. |
| `decided_by`, `decided_at` | Quién la decidió y cuándo. `decided_by.user_id` es el mismo id de `met.team.list()`. |
| `result` | Lo que salió al ejecutarla: una línea de texto, los archivos (`files`) y, si falló, `error_code`. |

Nunca trae la entrada cruda de la herramienta, credenciales (tampoco dentro de un texto, como
el error de un proveedor), datos de contacto de tus clientes, ids internos ni el nombre de un
modelo.

## Enterarte sin consultar

Suscribe tu endpoint a dos eventos (ver [Webhooks](webhooks.html)). Los dos traen la
aprobación completa, con la misma forma de `approvals.retrieve`:

| Evento | Cuándo |
|---|---|
| `approval.requested` | Un Met pidió una acción que necesita aprobación. |
| `approval.decided` | Una persona la aprobó (`status: approved`) o la rechazó (`status: rejected`). |

```ts
await met.webhooks.subscriptions.create({
  url: 'https://tu-sistema.com/met/eventos',
  enabled_events: ['approval.requested', 'approval.decided'],
});
```

Para saber cómo terminó una aprobada, lee la aprobación después de `approval.decided`
(`executed` o `failed`).

## Desde un asistente (MCP)

El servidor MCP de Meteor tiene `met_list_approvals` y `met_get_approval`, también de solo
lectura. Si le preguntas a tu asistente «¿qué tengo pendiente de aprobar?», te lo dice; para
aprobar, te manda a Met.

## Por qué no se aprueba por API

Las acciones que esperan aprobación son justo las que no se deshacen: un cobro, una factura
electrónica, una publicación, una campaña con presupuesto. Si una key pudiera aprobarlas, una
instrucción escondida en el mensaje de un contacto, o un error en tu integración, alcanzaría
para hacerlas sin que nadie del negocio lo viera. Por eso la decisión vive en Met, con la
persona que el negocio eligió en **Ajustes › Roles › ¿Quién aprueba?**.
