API de Zoan Cloud
La API de Zoan Cloud v1 te deja conectar tus propios sistemas con Zoan Automation usando HTTP y JSON, con los mismos permisos que ya administras en el portal y sin tocar la base de datos:
- Integrar el ERP o el CRM: tu sistema agrega trabajo a una cola cuando nace una factura o un pedido, y consulta después cómo terminó.
- Alimentar BI y reportes: lleva a Power BI, Looker o una hoja de cálculo los casos de flujos, las ejecuciones, los documentos procesados con IDP y el consumo de IA, con filtros por fecha y estado.
- Operar desde otro sistema: lanza un robot, inicia un caso de un flujo (también con su formulario de inicio), decide tareas humanas desde tu aplicación interna o revisa el registro de una ejecución sin abrir el portal.
- Enterarte sin preguntar: con los avisos salientes Zoan Cloud le avisa a tu sistema cuando termina una ejecución o un caso, cuando se crea o se decide una tarea y cuando un documento queda listo para validar.
La API es estable: en v1 solo se agregan campos y rutas, nunca se quitan ni cambian de tipo (ver Estabilidad).
Descargar la especificación OpenAPI 3.1 (YAML) · Descargar en JSON
Impórtala en Postman o Insomnia para tener todas las rutas listas para probar, o úsala para generar un cliente tipado en tu lenguaje. La misma especificación se sirve en GET https://api.cloud.zoansoftware.com/v1/openapi.json.
Cuentas de servicio y claves
Sección titulada «Cuentas de servicio y claves»Una integración no usa el usuario de una persona: usa una cuenta de servicio, una identidad de máquina con sus propios roles y su propia clave. Así, si alguien sale de la empresa o cambia su contraseña, la integración sigue funcionando, y cada sistema conectado queda identificado por separado en la auditoría.
Las cuentas se crean en el portal, en Administración › Claves de API. Se necesita el permiso api_key:manage, que por defecto tienen los roles Owner y Admin.
| Ajuste | Qué define |
|---|---|
| Nombre | Para reconocer la integración (p. ej. «ERP — carga de facturas»). |
| Roles | Los roles del tenant, incluidos los personalizados. No se puede asignar Owner ni Admin. |
| Ambientes permitidos | Los únicos ambientes en los que la clave puede leer u operar. |
| Vencimiento | Opcional. Después de esa fecha la cuenta deja de funcionar sola. |
| IPs permitidas | Opcional. Direcciones IP o rangos CIDR, IPv4 o IPv6 (p. ej. 203.0.113.10 o 2001:db8::/48). Cualquier otra IP recibe 403. |
La clave se muestra una sola vez
Sección titulada «La clave se muestra una sola vez»Al crear una clave, el portal la muestra completa una única vez (empieza por zk_). Cópiala en ese momento a tu gestor de secretos: Zoan Cloud no la guarda en claro y después solo se ven sus últimos 4 caracteres para reconocerla.
En la lista de la cuenta ves, por clave, cuándo se creó, si vence y su último uso con la IP desde la que llegó, para detectar claves olvidadas o usos inesperados.
Rotar y revocar sin cortes
Sección titulada «Rotar y revocar sin cortes»- Cada cuenta admite máximo 2 claves activas, justo lo necesario para cambiar de clave sin interrumpir la integración.
- Rotar crea una clave nueva y retira la anterior. Puedes dar una gracia de 0 a 48 horas en la que ambas funcionan: despliegas la nueva en tu sistema con calma y la vieja se apaga sola al terminar el plazo.
- Revocar apaga una clave de inmediato. Úsalo si una clave se filtró.
Autenticación
Sección titulada «Autenticación»Cada solicitud lleva la clave en la cabecera Authorization:
GET /v1/environments HTTP/1.1Host: api.cloud.zoansoftware.comAuthorization: Bearer zk_0123456789ab_EJEMPLOxxxxxxxxxxxxxxxxxxxxxxxx- URL base:
https://api.cloud.zoansoftware.com/v1 - Nunca pongas la clave en la URL (
?api_key=…,?token=…): las URLs quedan en historiales, proxies y registros. La API responde400 API_KEY_IN_URLy debes rotar esa clave, porque ya hay que darla por expuesta. - Sin doble factor: es una identidad de máquina, así que el doble factor de las personas no aplica. Las IPs permitidas y el vencimiento cumplen ese papel.
- La clave actúa con los permisos de sus roles en sus ambientes: ve exactamente lo que vería una persona con esos roles, incluido el enmascarado de datos sensibles (los campos sensibles de formularios y entradas llegan enmascarados igual que en el portal).
Para comprobar qué puede hacer una clave, llama a GET /me: devuelve la cuenta de servicio, sus roles y sus permisos efectivos.
Qué no se puede hacer con una clave
Sección titulada «Qué no se puede hacer con una clave»Una clave de API sirve para integrar, no para administrar. Por diseño:
- Solo funciona en
/v1. Cualquier otra ruta responde403 API_KEY_NOT_ALLOWED. - No inicia sesión en el portal ni en el Designer.
- No gestiona usuarios, roles, claves de API, SSO, facturación ni la configuración de la organización, aunque su rol tenga esos permisos.
- No entra a ambientes que no tenga asignados: para la clave, esos recursos no existen (
404). - No puede tener el rol Owner ni Admin.
Límites de uso
Sección titulada «Límites de uso»La API está disponible en todos los planes, también en Community: puedes conectarte y probarla desde el primer día. Cada plan fija cuánto puedes usarla:
| Plan | Solicitudes por minuto | Cuentas de servicio | Avisos salientes |
|---|---|---|---|
| Community | 60 | 1 | No incluidos |
| Core | 300 | 5 | 3 |
| Professional | 1.200 | 20 | 20 |
| Enterprise | Sin límite (o lo pactado en tu contrato) | Sin límite | Sin límite |
- Solicitudes por minuto, para toda la organización. Todas tus cuentas de servicio suman al mismo cupo: crear más claves no lo multiplica. Las llamadas que hace una persona desde el portal no cuentan.
- Cuentas de servicio y avisos salientes se cuentan en toda la organización (todos los ambientes). Al llegar al tope no se pueden crear más (
403 PLAN_LIMIT_REACHED, con el plan que lo amplía en el mensaje). Si bajas de plan, lo que ya creaste sigue funcionando: solo no puedes crear más hasta quedar por debajo del tope. - El uso y el tope de tu plan se ven en Facturación › Uso del plan, en Administración › Claves de API y en Avisos salientes.
Cabeceras de cupo
Sección titulada «Cabeceras de cupo»Cada respuesta a una solicitud con clave trae el estado del cupo del minuto, para que tu integración se regule antes de llegar al tope:
| Cabecera | Qué indica |
|---|---|
X-RateLimit-Limit | Solicitudes por minuto de tu plan. |
X-RateLimit-Remaining | Las que quedan en el minuto en curso. |
X-RateLimit-Reset | Cuándo se reinicia el cupo, en segundos Unix (UTC). |
En Enterprise sin límite estas cabeceras no se envían.
Qué hacer con un 429
Sección titulada «Qué hacer con un 429»Al pasarte del cupo, la API responde 429 RATE_LIMITED con la cabecera Retry-After (segundos que debes esperar) y el mismo valor en error.retryAfter:
{ "error": { "code": "RATE_LIMITED", "message": "La organización llegó al límite de 60 solicitudes por minuto de su plan. Espera 23 s o cambia de plan para ampliarlo.", "scope": "plan", "limit": 60, "retryAfter": 23 }}- Espera lo que dice
Retry-Afterantes de reintentar; no reintentes en un bucle sin pausa. - Regula el ritmo con
X-RateLimit-Remaining: si llega a 0, espera hastaX-RateLimit-Reset. - Si te quedas corto de forma habitual, agrupa consultas (filtros de fecha y
limit=100) o cambia de plan.
async function llamar(url, opciones, intentos = 3) { const r = await fetch(url, opciones); if (r.status !== 429 || intentos === 0) return r; const espera = Number(r.headers.get('Retry-After') ?? '1'); await new Promise((ok) => setTimeout(ok, espera * 1000)); return llamar(url, opciones, intentos - 1);}Límites generales
Sección titulada «Límites generales»Además del cupo del plan:
- 3000 solicitudes por clave cada 15 minutos, con las cabeceras
RateLimit-*. Al superarlas, también429 RATE_LIMITEDconRetry-After. - Un tope de claves rechazadas por red: 100 intentos con clave inválida cada 15 minutos desde la misma red. Si una integración mal configurada insiste con una clave vieja, la red queda en pausa un rato; corrige la clave antes de reintentar.
Paginación y filtros
Sección titulada «Paginación y filtros»Las listas devuelven una página y un cursor:
{ "data": [ ... ], "next_cursor": "eyJ0IjoiMjAyNi0xMC0wNV..." }limit: elementos por página, de 1 a 100 (por defecto 50).- Para la página siguiente, repite la misma consulta con
cursor=<next_cursor>. Cuandonext_cursoresnull, ya no hay más. - Orden: de lo más reciente a lo más antiguo. Los registros de una ejecución y los eventos de un caso vienen en orden cronológico.
from(incluido) yto(excluido): fecha u hora ISO 8601 (2026-10-01o2026-10-01T05:00:00Z). Contoexcluido, los meses encadenan sin solaparse:from=2026-10-01&to=2026-11-01.status: uno o varios separados por coma (status=running,incident).
Un cursor inválido o de otra consulta responde 400 INVALID_CURSOR; un filtro mal formado, 400 INVALID_QUERY.
Los recursos que viven en carpetas (procesos y ejecuciones) se listan solo de las carpetas a las que la clave tiene acceso, y aceptan folder: root (lo suelto en la raíz) o el id de una carpeta (esa y sus subcarpetas). folder solo acota: nunca muestra más de lo que la clave ve.
Reintentos seguros (Idempotency-Key)
Sección titulada «Reintentos seguros (Idempotency-Key)»Lanzar ejecuciones e iniciar casos aceptan la cabecera Idempotency-Key (un valor único por solicitud, de hasta 255 caracteres, p. ej. pedido-2026-0001):
- Si tu sistema repite la solicitud con la misma clave y el mismo cuerpo (porque no recibió respuesta), la API devuelve lo que creó la primera vez con
200, sin crear nada nuevo. - La misma clave con otro cuerpo responde
409 IDEMPOTENCY_KEY_REUSED. - La clave es de cada identidad: dos integraciones distintas pueden usar el mismo valor sin chocar.
Agregar un ítem a una cola es idempotente por su reference (ver Colas).
Errores
Sección titulada «Errores»Todas las respuestas de error tienen la misma forma:
{ "error": { "code": "FORBIDDEN", "message": "No tienes permiso para esta acción." } }Los errores de validación agregan errors con el campo y el motivo; los de límite agregan retryAfter.
| HTTP | Código | Qué significa | Qué hacer |
|---|---|---|---|
| 401 | API_KEY_INVALID | Falta la clave o no es válida. | Revisa la cabecera Authorization: Bearer zk_…. |
| 401 | API_KEY_REVOKED | La clave fue revocada (o terminó su gracia de rotación). | Usa la clave vigente de la cuenta. |
| 401 | API_KEY_EXPIRED | La clave venció. | Crea o rota una clave. |
| 401 | SERVICE_ACCOUNT_DISABLED | La cuenta de servicio está deshabilitada. | Pide a un administrador que la habilite. |
| 401 | SERVICE_ACCOUNT_EXPIRED | La cuenta de servicio venció. | Amplía o quita el vencimiento en el portal. |
| 403 | API_KEY_IP_NOT_ALLOWED | La solicitud llegó desde una IP fuera de las permitidas. | Agrega la IP o el rango en la cuenta. |
| 403 | API_KEY_NOT_ALLOWED | Ruta fuera de /v1: no está disponible con clave. | Usa solo las rutas de esta referencia. |
| 400 | API_KEY_IN_URL | La clave viajó en la URL. | Pásala en la cabecera y rota la clave. |
| 403 | FORBIDDEN (o código de permiso) | Los roles de la cuenta no tienen el permiso de la ruta. | Agrega el permiso al rol de la integración. |
| 404 | NOT_FOUND | No existe o está en un ambiente que la clave no tiene. | Revisa el id y los ambientes permitidos. |
| 400 | INVALID_CURSOR / INVALID_QUERY | Cursor o parámetros inválidos. | Repite la consulta original con el next_cursor recibido. |
| 422 | VALIDATION_ERROR | El cuerpo no cumple el esquema. | Mira errors para el campo y el motivo. |
| 403 | PLAN_LIMIT_REACHED | Se alcanzó el tope de cuentas de servicio o de avisos salientes del plan. | Borra lo que no uses o cambia al plan que indica el mensaje. |
| 403 | API_NOT_INCLUDED | El plan de la organización no permite usar la API con claves. | Habla con tu asesor de Zoan. |
| 403 | FOLDER_ACCESS_DENIED | Pediste folder= de una carpeta a la que la clave no tiene acceso. | Agrega la cuenta a esa carpeta o quita el filtro. |
| 409 | CONFLICT | El estado del recurso no permite la operación (p. ej. la tarea ya fue decidida). | Vuelve a leer el recurso antes de reintentar. |
| 409 | IDEMPOTENCY_KEY_REUSED | La Idempotency-Key ya se usó con otro cuerpo. | Usa una clave nueva para una solicitud distinta. |
| 409 | NOT_PUBLISHED / ORCHESTRATION_ARCHIVED | El flujo no tiene versión publicada o está archivado. | Publica o restaura el flujo. |
| 422 | INVALID_VARIABLES | Variables de un caso inválidas (desconocidas, de otro tipo u obligatorias que faltan). | Revisa inputs en GET /flows/{flowId}. |
| 422 | FORM_INVALID | Los campos del formulario de inicio no pasan sus reglas. | Mira errors para cada campo. |
| 429 | RATE_LIMITED | Se alcanzó el límite de solicitudes (del plan o de la clave). | Espera lo que indica Retry-After (qué hacer). |
Referencia de endpoints
Sección titulada «Referencia de endpoints»Todas las rutas son relativas a https://api.cloud.zoansoftware.com/v1. {envId} es el id de un ambiente (ver GET /environments). La columna Permiso es el que debe tener alguno de los roles de la cuenta.
Identidad
Sección titulada «Identidad»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /me | — | Cuenta de servicio, roles y permisos efectivos de la clave. |
| GET | /environments | — | Ambientes activos a los que tiene acceso la clave. |
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/flows | orchestration:list | Flujos del ambiente. |
| GET | /environments/{envId}/flows/{flowId} | orchestration:read | Un flujo con las variables de entrada de su versión publicada (tipo y obligatoriedad) y si se inicia con un formulario. |
| GET | /environments/{envId}/flows/{flowId}/start-form | orchestration:start u orchestration:start_form | El formulario de inicio publicado: sus campos son las claves de form al iniciar un caso. |
| POST | /environments/{envId}/flows/{flowId}/cases | orchestration:start (con variables) · orchestration:start u orchestration:start_form (con form) | Inicia un caso con la versión publicada. Con variables (y business_key opcional) o con form, los campos del formulario de inicio, validados con las mismas reglas que el portal (422 FORM_INVALID). Los campos de archivo no se pueden enviar por la API. Acepta Idempotency-Key. Responde 201 con el caso (sin título ni clave de negocio, que se leen con GET /cases/{caseId}). |
| GET | /environments/{envId}/cases | orchestration:list | Casos de flujos; filtros flow_id, status (running, waiting, incident, completed, cancelled), from/to por fecha de inicio. Sin orchestration:read_data, title y business_key llegan en null. |
| GET | /environments/{envId}/cases/{caseId} | orchestration:read | Detalle de un caso con sus pasos. Variables y datos de los pasos solo con orchestration:read_data; los datos sensibles llegan enmascarados. |
| GET | /environments/{envId}/cases/{caseId}/events | orchestration:read | Eventos de un caso, en orden cronológico. |
| POST | /environments/{envId}/cases/{caseId}/signals | orchestration:signal (o orchestration:operate) | Envía una señal a un caso que la espera en un paso Esperar evento. name es la señal, data sus datos (opcional) e idempotency_key (o la cabecera Idempotency-Key) evita aplicarla dos veces. Ver Enviar una señal a un caso. |
Procesos
Sección titulada «Procesos»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/processes | process:list | Procesos de las carpetas que ve la clave, con lo necesario para lanzarlos: plataforma (windows necesita máquina y sesión de robot; headless corre en Zoan Cloud o en una máquina), versión publicada y entradas declaradas por el robot (nombre, tipo, obligatoria, descripción, valores admitidos y valor por defecto). Filtros status (active, inactive), name (parte del nombre) y folder. |
| GET | /environments/{envId}/processes/{processId} | process:read | Un proceso (en la carpeta del proceso). |
Ejecuciones
Sección titulada «Ejecuciones»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| POST | /environments/{envId}/executions | execution:start | Lanza un proceso en una o varias máquinas (targets, máximo 50) con sus inputs. Un proceso headless puede ir a Zoan Cloud con agent_id: null. Todo o nada: si un destino no vale, no se crea ninguna. Acepta Idempotency-Key. |
| GET | /environments/{envId}/executions | execution:list | Ejecuciones de robots de las carpetas que ve la clave; filtros status (queued, running, paused, completed, failed, cancelled, stopped), process_id, folder, from/to por fecha de creación. |
| GET | /environments/{envId}/executions/{executionId} | execution:read | Detalle con entradas y salidas; las entradas sensibles llegan enmascaradas. |
| GET | /environments/{envId}/executions/{executionId}/logs | execution:logs | Registro de la ejecución en orden cronológico; filtro level (trace, debug, info, warn, warning, error, fatal). |
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/queues | queue:list | Colas del ambiente. |
| GET | /environments/{envId}/queues/{queueId}/items | queue-item:list | Ítems de la cola; filtros status (new, review, waiting_decision, in_progress, successful, failed, abandoned, retried, deleted), reference, from/to. Sin status no incluye los eliminados. |
| POST | /environments/{envId}/queues/{queueId}/items | queue-item:create | Agrega un ítem (reference, priority, specific_content, defer_until). Con reference es idempotente: si ya existe un ítem con esa referencia en la cola, devuelve ese (200, deduplicated: true) en vez de crear otro (201). |
Tareas humanas
Sección titulada «Tareas humanas»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/human-tasks | human_task:list | Tareas dirigidas a uno de los roles de la clave (o todas con human_task:view_all); filtros status (pending, claimed, completed, cancelled, expired), from/to. No incluye los datos ni las respuestas de los formularios. |
| POST | /environments/{envId}/human-tasks/{taskId}/decision | human_task:complete | Decide una tarea abierta dirigida a un rol de la clave (o cualquiera con human_task:manage). decision es una de decision_options; fields lleva los campos del formulario y comment es opcional. |
Documentos (IDP)
Sección titulada «Documentos (IDP)»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/documents | document:list | Documentos procesados con IDP; filtros status (pending, extracted, in_review, validated), project_id, reference, from/to. |
| GET | /environments/{envId}/documents/{documentId} | document:read | Detalle del documento con sus campos y la confianza de cada uno. |
| GET | /environments/{envId}/documents/{documentId}/values | document:read | Valores validados. Mientras el documento no esté validado, values es null. |
Consumo de IA
Sección titulada «Consumo de IA»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/ai-usage | audit:read | Totales y desgloses por día, origen y modelo (llamadas, tokens y costo en USD, separando lo incluido en el plan de lo cargado a tu cuenta del proveedor). Por defecto, el mes en curso (UTC); rango máximo de 366 días. Es el mismo dato del panel Consumo de IA. |
Auditoría
Sección titulada «Auditoría»| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /audit-events | audit:read | Eventos de la bitácora de la organización, del más reciente al más antiguo, con from, to, event_type, entity_type y cursor. Quien no administra la organización ve los eventos de la organización y los de sus ambientes. Para llevar la bitácora a tu sistema de forma continua, consulta con from igual a la fecha del último evento que ya tienes. Es la misma bitácora de Gobierno › Auditoría. |
Avisos salientes (webhooks)
Sección titulada «Avisos salientes (webhooks)»Suscripciones del ambiente a eventos que Zoan Cloud entrega con un POST JSON firmado. Cómo funcionan, los eventos y cómo verificar la firma: Avisos salientes.
| Método | Ruta | Permiso | Descripción |
|---|---|---|---|
| GET | /environments/{envId}/webhooks | webhook:list | Avisos del ambiente (sin el secreto: solo sus últimos 4 caracteres). |
| POST | /environments/{envId}/webhooks | webhook:manage y los permisos de cada evento | Crea un aviso (name, url https pública, events). Devuelve el secreto de firma una sola vez. Máximo 20 por ambiente y, en toda la organización, los que permita el plan (límites). |
| GET | /environments/{envId}/webhooks/{webhookId} | webhook:list | Un aviso. |
| PATCH | /environments/{envId}/webhooks/{webhookId} | webhook:manage | Cambia name, url, events o enabled (reactivar reinicia la cuenta de fallos). |
| DELETE | /environments/{envId}/webhooks/{webhookId} | webhook:manage | Borra el aviso y su registro. |
| POST | /environments/{envId}/webhooks/{webhookId}/rotate-secret | webhook:manage | Secreto nuevo (una vez); el anterior sigue firmando 24 horas. |
| POST | /environments/{envId}/webhooks/{webhookId}/test | webhook:manage | Envía un aviso de prueba webhook.ping. |
| GET | /environments/{envId}/webhooks/{webhookId}/deliveries | webhook:list | Entregas de los últimos 30 días; filtro status (pending, delivering, succeeded, failed, skipped). |
| POST | /environments/{envId}/webhooks/{webhookId}/deliveries/{deliveryId}/retry | webhook:manage | Reenvía una entrega fallida u omitida. |
El detalle de cada campo está en la especificación OpenAPI; los cuerpos de los avisos, en su sección webhooks.
Ejemplos
Sección titulada «Ejemplos»Los ejemplos usan datos ficticios. Guarda la clave en una variable de entorno para no escribirla en la línea de comandos:
export ZOAN_API_KEY="zk_0123456789ab_EJEMPLOxxxxxxxxxxxxxxxxxxxxxxxx"export ZOAN_API="https://api.cloud.zoansoftware.com/v1"Listar los ambientes
Sección titulada «Listar los ambientes»curl -s "$ZOAN_API/environments" \ -H "Authorization: Bearer $ZOAN_API_KEY"{ "data": [ { "id": "7c1e4a52-3b9d-4f0e-9a61-2d8f5b0c9e11", "name": "Producción", "code": "prod" }, { "id": "0f6b2d84-91ae-4c37-b5d2-6e3a8c1f7d20", "name": "Pruebas", "code": "qa" } ]}Casos con incidente en octubre
Sección titulada «Casos con incidente en octubre»ENV=7c1e4a52-3b9d-4f0e-9a61-2d8f5b0c9e11curl -s "$ZOAN_API/environments/$ENV/cases?status=incident&from=2026-10-01&to=2026-11-01&limit=100" \ -H "Authorization: Bearer $ZOAN_API_KEY"{ "data": [ { "id": "a3d9f1c0-5e27-4b8a-9c44-71f2e6b0d583", "flow_id": "5b8e0d17-2c6f-4a93-8e1b-c4a7f9d2e604", "flow_name": "Causación de facturas", "status": "incident", "title": "Factura FV-10482", "business_key": "FV-10482", "start_source": { "kind": "queue", "queue_item_id": "e2c47a19-8f3b-4d06-a5e1-9b0d6c3f2a78" }, "step_count": 4, "ended_reason": null, "started_at": "2026-10-03T14:12:08Z", "ended_at": null, "last_activity_at": "2026-10-03T14:13:51Z" } ], "next_cursor": "eyJ0IjoiMjAyNi0xMC0wM1QxNDoxMjowOFoiLCJpZCI6ImEzZDlmMWMwIn0"}Recorrer todas las páginas
Sección titulada «Recorrer todas las páginas»Repite la misma consulta con el next_cursor hasta que llegue null (requiere jq):
URL="$ZOAN_API/environments/$ENV/executions?from=2026-10-01&to=2026-11-01&limit=100"CURSOR=""while : ; do PAGE=$(curl -s "$URL${CURSOR:+&cursor=$CURSOR}" -H "Authorization: Bearer $ZOAN_API_KEY") echo "$PAGE" | jq -c '.data[]' >> ejecuciones-octubre.jsonl CURSOR=$(echo "$PAGE" | jq -r '.next_cursor // empty | @uri') [ -z "$CURSOR" ] && breakdoneAgregar un ítem a una cola
Sección titulada «Agregar un ítem a una cola»Con reference, reintentar la misma solicitud es seguro: si el ítem ya existe, no se duplica.
QUEUE=3e9a7c51-6d2b-4f84-b0a3-8c1e5d7f9b26curl -s -X POST "$ZOAN_API/environments/$ENV/queues/$QUEUE/items" \ -H "Authorization: Bearer $ZOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "reference": "FV-10483", "priority": "high", "specific_content": { "nit": "900123456", "proveedor": "Suministros Andinos S.A.S.", "valor": 1850000 } }'Respuesta 201 Created (o 200 con "deduplicated": true si ya existía):
{ "item": { "id": "c81f2b6d-4a07-49e3-9d15-6a2e0f8b3c47", "queue_id": "3e9a7c51-6d2b-4f84-b0a3-8c1e5d7f9b26", "reference": "FV-10483", "priority": "high", "status": "new", "specific_content": { "nit": "900123456", "proveedor": "Suministros Andinos S.A.S.", "valor": 1850000 }, "attempts": 0, "created_at": "2026-10-06T15:02:44Z", "updated_at": "2026-10-06T15:02:44Z" }, "deduplicated": false}Lanzar un proceso
Sección titulada «Lanzar un proceso»Busca el proceso para conocer su plataforma y sus entradas:
curl -s "$ZOAN_API/environments/$ENV/processes?name=facturas" \ -H "Authorization: Bearer $ZOAN_API_KEY"{ "data": [ { "id": "7d1f3c2a-0000-4000-8000-000000000001", "name": "Registrar facturas", "status": "active", "folder_id": null, "folder_name": null, "platform": "headless", "package": { "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "name": "Facturación" }, "version": { "id": "9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a", "semver": "1.4.0", "number": 7, "published_at": "2026-10-02T13:05:00Z" }, "inputs": [ { "name": "fecha_corte", "type": "date", "required": true, "description": "Último día a registrar" }, { "name": "modo", "type": "string", "required": false, "enum": ["rapido", "completo"], "default": "rapido" } ], "outputs": [{ "name": "registradas", "type": "number" }], "max_duration_minutes": 120, "created_at": "2026-09-14T10:00:00Z", "updated_at": "2026-10-02T13:05:00Z" } ], "next_cursor": null}Y lánzalo (un proceso headless puede ir a Zoan Cloud con agent_id: null; uno Windows necesita agent_id y robot_session_id):
curl -s -X POST "$ZOAN_API/environments/$ENV/executions" \ -H "Authorization: Bearer $ZOAN_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: corte-2026-10-15" \ -d '{ "process_id": "7d1f3c2a-0000-4000-8000-000000000001", "targets": [{ "agent_id": null }], "inputs": { "fecha_corte": "2026-10-15" } }'Iniciar un caso de un flujo
Sección titulada «Iniciar un caso de un flujo»Con variables de entrada (las de GET /flows/{flowId}):
FLOW=5b8e0d17-2c6f-4a93-8e1b-c4a7f9d2e604curl -s -X POST "$ZOAN_API/environments/$ENV/flows/$FLOW/cases" \ -H "Authorization: Bearer $ZOAN_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: pedido-PED-2041" \ -d '{ "variables": { "numero_pedido": "PED-2041", "total": 250000 }, "business_key": "PED-2041" }'O con los campos de su formulario de inicio (los de GET /flows/{flowId}/start-form), validados igual que en el portal:
curl -s -X POST "$ZOAN_API/environments/$ENV/flows/$FLOW/cases" \ -H "Authorization: Bearer $ZOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "form": { "solicitante": "Ana Pérez", "monto": 1250000, "urgente": true } }'Respuesta 201 Created (o 200 si la Idempotency-Key ya había iniciado ese caso):
{ "id": "a3d9f1c0-5e27-4b8a-9c44-71f2e6b0d583", "flow_id": "5b8e0d17-2c6f-4a93-8e1b-c4a7f9d2e604", "flow_name": "Anticipos", "flow_version": 3, "status": "running", "start_source": { "kind": "form" }, "started_at": "2026-10-16T15:02:44Z", "ended_at": null, "ended_reason": null}Si un campo no cumple sus reglas, la respuesta es 422 FORM_INVALID con errors por campo.
Decidir una tarea humana
Sección titulada «Decidir una tarea humana»Primero lista las pendientes para conocer sus decision_options y sus form_fields:
curl -s "$ZOAN_API/environments/$ENV/human-tasks?status=pending" \ -H "Authorization: Bearer $ZOAN_API_KEY"Después envía la decisión:
TASK=9d4b6e20-1f7a-4c58-8b39-e5a0c2d7f164curl -s -X POST "$ZOAN_API/environments/$ENV/human-tasks/$TASK/decision" \ -H "Authorization: Bearer $ZOAN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "decision": "Aprobar", "fields": { "centro_costo": "CC-204" }, "comment": "Aprobado desde el ERP" }'{ "id": "9d4b6e20-1f7a-4c58-8b39-e5a0c2d7f164", "title": "Aprobar pago FV-10482", "status": "completed", "decision": "Aprobar", "completed_at": "2026-10-06T15:10:02Z", "completed_by_name": "ERP — aprobaciones"}Si la tarea ya fue decidida o cancelada, la respuesta es 409 CONFLICT.
Enviar una señal a un caso
Sección titulada «Enviar una señal a un caso»Cuando un caso espera un evento en un paso Esperar evento, tu sistema le avisa con una señal. Por ejemplo, la pasarela de pagos confirma el pago de un pedido:
CASE=3b7f2c10-8e4d-4a91-b6c5-0d2e9f7a1c38curl -s -X POST "$ZOAN_API/environments/$ENV/cases/$CASE/signals" -H "Authorization: Bearer $ZOAN_API_KEY" -H "Content-Type: application/json" -H "Idempotency-Key: pago-PAY-88213" -d '{ "name": "pago-confirmado", "data": { "referencia": "PAY-88213", "total": 1850000 } }'{ "case_id": "3b7f2c10-8e4d-4a91-b6c5-0d2e9f7a1c38", "signal": "pago-confirmado", "delivered_to": [ { "step_id": "a1d5e7c2-4b90-4f38-9e61-7c2b0d8f5a14", "element_id": "esperar_pago" } ], "status": "running", "received_at": "2026-10-19T15:04:22Z", "duplicate": false}| Campo | Qué es |
|---|---|
name | Obligatorio. El nombre de la señal que espera el paso (1 a 100 caracteres). |
data | Opcional. Un objeto con los datos de la señal; el paso guarda en variables los campos que tenga configurados, con su tipo validado. |
idempotency_key | Opcional (1 a 200 caracteres). También se acepta la cabecera Idempotency-Key. Con la misma clave y el mismo contenido, la API devuelve la misma respuesta con "duplicate": true sin aplicar la señal otra vez: tu sistema puede reintentar sin miedo. |
En la respuesta, delivered_to lista los pasos que recibieron la señal (varios, si hay ramas paralelas esperando la misma) y status es el estado del caso después de recibirla.
| HTTP | Código | Qué significa |
|---|---|---|
| 404 | NOT_FOUND | El caso no existe o está en un ambiente que la clave no tiene. |
| 409 | SIGNAL_NOT_EXPECTED | El caso no está esperando esa señal. |
| 409 | CASE_ENDED | El caso ya terminó. |
| 409 | IDEMPOTENCY_CONFLICT | La misma clave de idempotencia se usó con otro nombre u otros datos. |
| 409 | INSTANCE_BUSY | El caso está ocupado en este momento; reintenta en unos segundos. |
| 422 | SIGNAL_DATA_INVALID | Los datos no sirven para las variables del paso (falta uno obligatorio o no cuadra el tipo). El caso sigue esperando; corrige los datos y envíala de nuevo. |
Cada envío cuenta para los límites de uso de la clave, como cualquier otra solicitud.
Leer los valores validados de un documento
Sección titulada «Leer los valores validados de un documento»DOC=4f2c8a91-7b3e-4d60-a5c2-1e9b7d0f3a85curl -s "$ZOAN_API/environments/$ENV/documents/$DOC/values" \ -H "Authorization: Bearer $ZOAN_API_KEY"{ "document_id": "4f2c8a91-7b3e-4d60-a5c2-1e9b7d0f3a85", "validated": true, "validated_at": "2026-10-05T19:44:10Z", "values": { "numero_factura": "FV-10482", "nit_emisor": "900123456", "fecha": "2026-10-02", "total": 1850000 }}Consumo de IA del mes
Sección titulada «Consumo de IA del mes»Sin from ni to, devuelve el mes en curso (UTC):
curl -s "$ZOAN_API/environments/$ENV/ai-usage" \ -H "Authorization: Bearer $ZOAN_API_KEY"{ "environment_id": "7c1e4a52-3b9d-4f0e-9a61-2d8f5b0c9e11", "from": "2026-10-01T00:00:00Z", "to": "2026-11-01T00:00:00Z", "currency": "USD", "totals": { "calls": 1240, "input_tokens": 3815200, "output_tokens": 402950, "cost_usd": 9.87, "cost_included_usd": 9.87, "cost_own_usd": 0 }, "by_day": [ { "date": "2026-10-01", "calls": 210, "input_tokens": 640100, "output_tokens": 68020, "cost_usd": 1.66, "cost_included_usd": 1.66, "cost_own_usd": 0 } ], "by_source": [ { "source": "idp", "calls": 820, "input_tokens": 2950000, "output_tokens": 301400, "cost_usd": 7.42, "cost_included_usd": 7.42, "cost_own_usd": 0 } ], "by_model": [ { "model": "gpt-4.1-mini", "kind": "chat", "calls": 1240, "input_tokens": 3815200, "output_tokens": 402950, "cost_usd": 9.87, "cost_included_usd": 9.87, "cost_own_usd": 0 } ]}Estabilidad de v1
Sección titulada «Estabilidad de v1»Puedes construir sobre v1 con tranquilidad:
- En v1 solo se agregan campos y rutas; ninguno se quita ni cambia de tipo.
- Ignora los campos que no conozcas: así tu integración sigue funcionando cuando aparezcan datos nuevos.
- Un cambio incompatible, si alguna vez hace falta, llegará como una versión nueva (
/v2) que convivirá con v1.
Siguientes pasos
Sección titulada «Siguientes pasos»- Avisos salientes (webhooks) — que Zoan Cloud le avise a tu sistema cuando algo termina, con firma verificable.
- Usuarios y roles — crea un rol propio con lo mínimo para tu integración.
- Colas de trabajo — cómo procesan los robots los ítems que agregas por API.
- Configuración — ajustes de la organización.