Docs / API Reference / Workflows
API Reference

Workflows

Automatizaciones alimentadas por los mismos eventos que disparan los webhooks. Define el grafo en JSON (o dibújalo en el editor visual del panel), nosotros lo ejecutamos con historial por nodo.

Modelo de un workflow

Un workflow tiene un nodo disparador (manual o evento) y un grafo de nodos conectados por aristas en definicion. Cada nodo guarda su configuración y su salida para que puedas depurar la ejecución paso a paso.

{
  "id": 42,
  "nombre": "Notificar cuando se autoriza una factura",
  "descripcion": null,
  "activo": true,
  "trigger_tipo": "evento",
  "evento": "factura.autorizada",
  "eventos": ["factura.autorizada"],
  "definicion": {
    "nodes": [
      { "id": "evento_1", "type": "trigger.evento", "data": { "eventos": ["factura.autorizada"] } },
      {
        "id": "http_1",
        "type": "action.http",
        "data": {
          "method": "POST",
          "url": "https://hooks.example.com/notificar",
          "auth": { "tipo": "bearer", "secreto": "CRM_TOKEN" },
          "body_tipo": "json",
          "body": "{ \"factura\": \"{{trigger.numero_comprobante}}\", \"total\": \"{{trigger.total}}\" }",
          "reintentos": 2
        }
      }
    ],
    "edges": [{ "source": "evento_1", "target": "http_1" }]
  },
  "created_at": "2026-07-03T10:00:00",
  "updated_at": "2026-07-03T10:00:00"
}

Autenticación

Los workflows se gestionan con la sesión de usuario del panel (Authorization: Bearer). Las API keys (X-API-Key) están acotadas a comprobantes, clientes, servicios, sucursales y eventos — no acceden a /workflows.

Tipos de trigger (trigger_tipo)

Parámetro Tipo Descripción
manual optional string Se ejecuta al llamar a POST /workflows/{id}/run.
evento optional string Se dispara con cualquiera de los eventos de data.eventos del nodo trigger.evento (factura.autorizada, cobro.registrado, stock.bajo_minimo…). Lista completa en GET /workflows/eventos.

Tipos de nodo

El catálogo vivo está en GET /api/v1/workflows/nodos. Los nodos de acción aceptan además reintentos (0-3, para errores temporales) y en_error (detener o continuar).

Parámetro Tipo Descripción
trigger.manual optional trigger Nodo de entrada para ejecuciones manuales (POST /run).
trigger.evento optional trigger Nodo de entrada por evento. data.eventos: lista de nombres del catálogo.
action.http optional acción Llamada HTTP: method, url, query y headers ([{clave, valor}]), auth {tipo: bearer|basic|api_key, secreto}, body_tipo (json|form|texto|ninguno), body, timeout_s (1-30), fallar_si_no_2xx. Salida: {status, ok, headers, json | texto}. URLs internas bloqueadas (anti-SSRF).
action.webhook optional acción POST con los datos en JSON y firma HMAC SHA-256 (X-Emitoo-Signature) usando el secreto de data.secreto.
action.email optional acción Envía un correo con el SMTP de tu empresa (to, subject, body con variables).
branch.if optional lógica data.condiciones [{campo, op, valor}] y data.modo (todas|alguna). Sigue la arista con sourceHandle 'true' o 'false'; la otra rama se salta.
flow.esperar optional lógica Pausa el flujo data.segundos (1-300).
transform.set optional datos Define datos nuevos: data.campos [{clave, valor}] (valor con variables).
transform optional datos Copia campos de la entrada con otro nombre ({destino: ruta-origen}), sin ejecutar código.
action.buscar optional datos Busca personas/empresas, servicios, facturas, guías o retenciones. Devuelve {entidad, total, registros}.
action.log optional utilidad Devuelve sus inputs como output. Útil para depurar el flujo.

Variables

Cualquier texto de la configuración acepta {{ruta}}: {{trigger.total}} (datos del disparador), {{steps.http_1.json.id}} (salida de un nodo anterior), {{entrada.campo}}, {{empresa.ruc}}, {{hoy}}. Si el texto es solo una variable, conserva su tipo (número, objeto); dentro de un texto se interpola. Una variable que no existe queda vacía y se anota en el historial.

Listar workflows

GET /api/v1/workflows — Lista los workflows de tu empresa (con su última ejecución)

Crear un workflow

POST /api/v1/workflows — Crea un workflow a partir de un grafo

Body

Parámetro Tipo Descripción
nombre required string Nombre legible. Máx 160 caracteres.
trigger_tipo required string 'manual' o 'evento'. Si la definición trae un nodo disparador, se deriva de él.
eventos optional string[] Eventos que lo disparan (trigger_tipo='evento'). Si el nodo trigger.evento no trae data.eventos, se toman de aquí. El campo 'evento' (uno solo) sigue aceptándose.
definicion optional object Grafo del workflow: { nodes: [{id, type, data}], edges: [{source, target, sourceHandle?}] }. Es el formato del editor visual (React Flow).
descripcion optional string Descripción opcional.
activo optional boolean Default: true. Un workflow activo debe pasar la validación (ver POST /workflows/validar); si no, responde 400. Con false se guarda como borrador.
curl -X POST https://api.emitoo.io/api/v1/workflows \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "nombre": "Notificar facturas autorizadas",
    "trigger_tipo": "evento",
    "eventos": ["factura.autorizada"],
    "definicion": {
      "nodes": [
        { "id": "evento_1", "type": "trigger.evento", "data": { "eventos": ["factura.autorizada"] } },
        {
          "id": "http_1",
          "type": "action.http",
          "data": {
            "method": "POST",
            "url": "https://hooks.example.com/notificar"
          }
        }
      ],
      "edges": [{ "source": "evento_1", "target": "http_1" }]
    }
  }'

Obtener / actualizar / eliminar

GET /api/v1/workflows/[id] — Devuelve un workflow con su definición

PUT /api/v1/workflows/[id] — Actualiza nombre, definición o estado activo

DELETE /api/v1/workflows/[id] — Borra el workflow y su historial

POST /api/v1/workflows/validar — Valida una definición sin guardarla: { problemas: [{node_id, campo, mensaje, nivel}], errores, avisos }

Ejecutar manualmente

POST /api/v1/workflows/[id]/run — Lanza el workflow en segundo plano y devuelve el run en estado running (202)

Body

Parámetro Tipo Descripción
payload optional object Datos iniciales: llegan a los nodos como {{trigger.…}}.
curl -X POST https://api.emitoo.io/api/v1/workflows/42/run \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "payload": { "numero_comprobante": "001-001-000000123", "total": 115.5 } }'

# Responde 202 con el run en estado "running"; consulta su resultado:
curl https://api.emitoo.io/api/v1/workflows/runs/{run_id} \
  -H "Authorization: Bearer $USER_TOKEN"

Historial de ejecuciones

GET /api/v1/workflows/runs — Ejecuciones de todos tus workflows (filtros workflow_id, estado, limit ≤ 200, offset)

GET /api/v1/workflows/[id]/runs — Ejecuciones de un workflow, más recientes primero

GET /api/v1/workflows/runs/[run_id] — Detalle de un run, con configuración y salida por nodo

POST /api/v1/workflows/runs/[run_id]/reejecutar — Vuelve a ejecutar con el mismo payload (202)

Cada run incluye: estado (running, completed, failed), payload del disparador, duración y, por cada nodo, su configuración ya resuelta, salida, error, intentos y duración. Los nodos de una rama no tomada aparecen como skipped.

Secretos

Tokens y claves de APIs externas. Se guardan cifrados, el valor nunca vuelve a salir por la API y se tapa (***) en el historial. Los nodos los usan por nombre: auth.secreto en action.http y secreto en action.webhook.

GET /api/v1/workflows/secretos — Lista nombre, pista (últimos 4 caracteres), último uso y workflows que lo usan

POST /api/v1/workflows/secretos — Crea un secreto: { nombre, valor, descripcion? }

PUT /api/v1/workflows/secretos/[id] — Rota el valor o cambia la descripción

DELETE /api/v1/workflows/secretos/[id] — Borra el secreto (409 si algún workflow lo usa)

Catálogos

GET /api/v1/workflows/nodos — Catálogo de tipos de nodo

GET /api/v1/workflows/eventos — Catálogo de eventos con campos y payload de ejemplo (filtro opcional ?documento=factura)

GET /api/v1/workflows/eventos/[nombre]/ejemplo — Último payload real de ese evento en tu empresa (o uno de ejemplo)

Plantillas

Flujos listos para usar: recordatorios de cobro, cobranza de facturas vencidas (1, 7, 15 y 30 días, con el evento factura.en_mora), agradecimiento de pago, alertas de rechazo del SRI, stock bajo e integraciones con tu ERP o tu chat. El workflow se crea inactivo para revisarlo antes de activarlo.

GET /api/v1/workflows/plantillas — Plantillas con su definición, eventos, requisitos y los datos que piden

POST /api/v1/workflows/desde-plantilla — Crea un workflow inactivo: { plantilla_id, nombre?, parametros: { email_equipo, url_api… } }

Cómo fluye el payload

La salida de cada nodo es la entrada del siguiente según las aristas del grafo. En action.http y action.webhook, si el cuerpo JSON está vacío se envía la entrada recibida tal cual.