En esta sección
Guías / Operación del workspace

Operación del workspace

Consumo y facturación, archivos, conversaciones, recordatorios, autopiloto y grupos de agentes — lo que se consulta cuando ya estás en producción.

Cinco dominios que se consultan juntos, y siempre por la misma razón: algo ya está corriendo en producción y necesitas saber cuánto está gastando, quién lo está atendiendo o dónde quedó un archivo. No son cosas que se leen aprendiendo; son las que se buscan a las once de la noche.

Cuánta Energía estás gastando

La Energía se debita por ejecución. Si tu integración dispara Mets, esto es lo que te dice cuánto cuesta antes de que te sorprenda la factura:

const uso = await met.billing.consumption({ from: '2026-07-01', to: '2026-07-31' });
const ejec = await met.billing.executions({ limit: 50 });

consumption es el agregado del período; executions es el detalle, una fila por ejecución con su costo. Cuando el total no cuadra con lo que esperabas, la respuesta está en el detalle: casi siempre es un Met que se llama a sí mismo en un bucle, o un flujo que corre más veces de las que creías.

const saldo = await met.billing.subscription();
const recarga = await met.billing.autoRecharge();

autoRecharge importa más de lo que parece si tu integración es desatendida: sin recarga automática, quedarse sin Energía detiene las ejecuciones, y eso se ve como "la API dejó de responder" cuando en realidad es saldo. Consúltala antes de culpar al código.

El resto es lectura de la relación comercial: invoices(), transactions(), plans(), addons() y myAddons(). Y access(), que responde qué tiene habilitado el plan actual — útil para no llamar a un endpoint que va a devolver 403 por plan y no por permisos.

Archivos del workspace

La Mediateca son los archivos del workspace, con carpetas propias:

const imagenes = await met.assets.list({ mime_prefix: 'image/', limit: 50 });
const subido = await met.assets.upload(blob, {
  filename: 'propuesta.pdf',
  contentType: 'application/pdf',
  folder_id: carpeta.id,
});

list devuelve un array (no una página con cursor) y pagina con limit/offset. Además de mime_prefix filtra por folder_id, search y source — y ese último es el que sirve para auditar: distingue lo que subió una persona (upload) de lo que salió de un ítem, de lo que generó un Met (generated) o un flujo (flow_run).

En upload, filename es obligatorio: es lo que determina la extensión del objeto en storage, y sin ella el archivo queda sin tipo reconocible.

Dos cosas que ahorran tiempo:

Las miniaturas no las generas tú. Storage reescala en el borde, así que para mostrar un archivo en chico se pide ya dimensionado en vez de bajar el original. Está en Imágenes, y la diferencia medida es de 870 KB a 15 KB.

cleanupProvisional existe porque una subida que empieza y no termina deja el archivo huérfano. Corre en simulación por defecto:

const previo = await met.assets.cleanupProvisional();       // simula
await met.assets.cleanupProvisional(true);                  // aplica

Mira el resultado antes de pasar true. No es reversible.

Conversaciones

Una conversación es el hilo con un contacto. La distinción que hay que tener clara:

const principal = await met.conversations.main();
const todas = await met.conversations.list();

main() devuelve la conversación principal del workspace — la del panel, donde el equipo habla con el Met. list() devuelve todas, incluidas las de cada contacto. Si buscabas el historial de un contacto, el camino corto es met.contacts.messages(id), no recorrer list().

threadMessages(threadId) baja los mensajes de un hilo derivado, que es lo que se arma cuando alguien responde dentro de un mensaje en vez de al final.

Recordatorios

Un recordatorio agenda un mensaje al contacto para una fecha futura. Eso es lo primero que hay que tener claro: siempre se envía. No existe un modo "nota interna" — note es un campo para el equipo, no un interruptor que evite el envío.

await met.reminders.create({
  contact_id: 42,
  scheduled_for: '2026-08-05T14:00:00Z',
  message: 'Te escribo para confirmar si firmaste la propuesta',
  note: 'Seguimiento de la propuesta de julio',   // interno, no viaja
});

A la hora agendada, un despachador se lo manda al contacto por su canal. El canal sale del contacto, así que no hay que elegirlo.

scheduled_for va en ISO 8601 y tiene que ser futuro. Con offset (2026-08-05T09:00:00-05:00 o el Z del ejemplo) es un instante exacto; sin offset se interpreta en la zona horaria del workspace. Manda el offset si lo calculas en tu servidor: es la diferencia entre las 9 de la mañana del cliente y las 9 de la mañana de tu proceso.

Va con plantilla de WhatsApp y no con texto libre por lo mismo que las difusiones: un recordatorio se dispara días después del último mensaje de la persona, o sea fuera de la ventana de 24 horas, donde solo pasan plantillas aprobadas. Por eso el workspace necesita tener una plantilla de recordatorio por defecto configurada (Ajustes): sin ella, create responde 400. Tu message va como el cuerpo de esa plantilla.

Si quieres una plantilla distinta de la de por defecto, pásala explícita — y entonces language es obligatorio:

await met.reminders.create({
  contact_id: 42,
  scheduled_for: '2026-08-05T14:00:00Z',
  template_name: 'seguimiento_propuesta',
  language: 'es',
  variables: { '1': 'Ana' },                      // los huecos de la plantilla
});

list({ contactId, status }), update y cancel completan el CRUD. update mueve la fecha o cambia el texto, y solo funciona mientras está pendiente; cancel lo detiene antes de que se despache. Cancela en cuanto el motivo deja de existir: si no, al contacto le llega un mensaje fuera de contexto.

Autopiloto: cuándo contesta el Met y cuándo un humano

Por defecto el Met atiende. El autopiloto es el interruptor:

await met.contacts.setAutopilot(42, false);      // que atienda un humano
await met.contacts.pauseAutopilot(42, 30);       // 30 minutos, y vuelve solo
await met.contacts.setAutopilot(42, true);       // devolvérselo al Met

Usa pause y no setAutopilot(false) para una intervención puntual. Es la decisión que más se equivoca: apagar el autopiloto es permanente hasta que alguien lo prenda, y lo que sigue es un contacto que quedó sin atención automática durante semanas porque nadie se acordó. pause con minutos se reanuda solo; pause(id, 0) reanuda ya.

markRead(id) marca la conversación como leída, para que tu integración no deje el panel del equipo lleno de no-leídos que ya procesaste.

Grupos de agentes

Son grupos de personas —los agentes humanos del chat—, no de Mets. Sirven para enrutar y asignar conversaciones a un equipo en vez de a un individuo:

const g = await met.agentGroups.create({ name: 'Soporte técnico' });
await met.agentGroups.addMember(g.id, userId);
const miembros = await met.agentGroups.members(g.id);

addMember recibe un user_id, y ahí está la confusión que conviene evitar: si buscabas agrupar Mets, eso no existe como grupo — un Met se acota con sus habilidades y herramientas.

Gestionarlos pide rol de supervisor o admin, así que una key con scope pero de un usuario sin ese rol recibe 403. Es permiso, no plan.

Todo lo de esta guía opera sobre el workspace de la key. Una key de partner tiene su propia superficie: mira la API de Partners.