API
Todas las rutas cuelgan de https://dash.openwaf.dev/v1/orgs/{org} y aceptan un token de la API de OpenWAF (owf_…) o la sesión del panel. Las lecturas necesitan readonly; las escrituras, un admin de toda la organización, llevan X-Change-Reason (queda en el registro de auditoría) y aceptan ?dry_run=true para validar sin guardar.
| Ruta | Qué hace |
|---|---|
GET /tasks | Resumen: enabled, requirements, quota, usage, kill y todas las tareas. Se puede leer antes de aprobar el acceso. |
POST /tasks | Crea una tarea; 201 {"task", "webhook_secret"} (el secreto solo si hay webhook, una vez) |
GET /tasks/{task} | Lee una tarea ({task} es su id o su nombre) |
PATCH /tasks/{task} | Cambia cualquier campo editable; "rotate_webhook_secret": true genera un secreto nuevo |
DELETE /tasks/{task} | La borra (204) |
POST /tasks/{task}/run | La ejecuta ahora; 202 con la ejecución |
GET /tasks/{task}/runs?limit=&before= | Ejecuciones, de la más reciente a la más antigua: {"items", "next"} |
GET /tasks/browser-profiles?key_id= | Perfiles de una clave de navegador: {"items": [{"id", "name"}]} |
GET /task-runs/{run} | Una ejecución con sus approvals y artifacts |
GET /task-runs/{run}/logs?after=<seq> | Líneas de registro tras seq: {"items": [{"seq", "at", "level", "type", "message"}]} |
GET /task-runs/{run}/artifacts/{id} | Una captura (image/jpeg o image/png) |
GET /task-runs/{run}/recording | 302 al fichero de la grabación, si la ejecución grabó |
POST /task-runs/{run}/cancel | Cancela una ejecución; responde con la ejecución |
GET /task-approvals?status=&task= | Aprobaciones: {"items"}; status es pending, approved, rejected, expired, executed o failed |
GET /task-approvals/{id} | Una aprobación |
POST /task-approvals/{id}/approve | {"payload_sha256", "reason"}; responde con la aprobación |
POST /task-approvals/{id}/reject | {"reason"}; responde con la aprobación |
Resumen
{"enabled": true,
"requirements": {"browsers": true, "egress": true, "email_verified": true, "two_factor": true},
"quota": {"runs_per_month": 200, "max_tasks": 5, "max_concurrent": 1},
"usage": {"period_start": "2026-10-01T00:00:00Z", "period_end": "2026-11-01T00:00:00Z",
"runs": 14, "active": 0, "pending_approvals": 1},
"kill": false,
"tasks": [ … ]}kill es true mientras el servicio está en pausa para todas las organizaciones: no empieza ninguna ejecución.
Tarea
{"id": "…", "name": "guestbook", "description": "", "kind": "script",
"schedule": {"cron": "0 9 * * *", "timezone": "Europe/Madrid"},
"paused": false,
"browser": {"key_id": "…", "key_name": "ci-agent", "profile": "", "recording": false},
"allow": ["example.com"],
"script": "export default async function ({ page, task }) { … }",
"input": {}, "state": {},
"max_run_minutes": 10,
"approval": {"policy": "required", "expire_minutes": 120, "relaxed_domains": []},
"action_limits": [{"domain": "example.com", "min_interval_minutes": 30, "max_per_day": 4}],
"webhook": {"url": "https://hooks.example.com/openwaf", "secret_set": true},
"pool": "browsers", "egress_agent": null,
"next_run_at": "2026-10-30T08:00:00Z",
"last_run": {"id": "…", "status": "succeeded", "finished_at": "2026-10-29T08:00:41Z"},
"created_at": "…", "updated_at": "…"}| Campo | Reglas |
|---|---|
name | Minúsculas, dígitos y guiones, hasta 63, único en la organización |
kind | script o agent; no se puede cambiar |
schedule | {"cron", "timezone"} (5 campos, zona IANA, como mucho cada 15 minutos) o {"at"} para una sola ejecución |
browser | key_id de una clave de navegador de la organización, nombre de profile (vacío para un navegador limpio), recording |
allow | De 1 a 20 dominios: example.com o *.example.com |
script | Solo script: módulo ES de hasta 256 KiB. Mira el inicio rápido del script. |
agent | Solo agent: {"goal", "egress_target", "model", "max_steps"}. Mira el inicio rápido del agente. |
input | JSON de hasta 64 KiB que reciben el script o el agente |
max_run_minutes | De 1 a 30 |
approval | expire_minutes de 10 a 1440. policy y relaxed_domains son de solo lectura; mira políticas. |
action_limits | Límites por dominio más estrictos |
webhook | {"url"} para fijarlo, null para quitarlo. Mira webhook. |
state, pool, egress_agent, next_run_at y last_run son de solo lectura.
Ejecución
{"id": "…", "task_id": "…", "task_name": "guestbook", "number": 12, "trigger": "schedule",
"status": "awaiting_approval",
"created_at": "…", "started_at": "…", "finished_at": null, "error": "",
"output": {"posted": "pending approval"},
"steps": 0, "browser_seconds": 38, "model_calls": 0, "prompt_tokens": 0, "completion_tokens": 0,
"blocked_requests": 0, "live_url": null, "recording_available": false, "egress_agent": null,
"approvals": [ … ],
"artifacts": [{"id": "…", "name": "before", "content_type": "image/jpeg", "size": 81234, "created_at": "…"}]}status es uno de queued, running, awaiting_approval, executing, succeeded, failed, rejected, expired, timed_out y canceled. trigger es schedule o manual. live_url solo tiene valor mientras la ejecución tiene navegador.
Aprobación
{"id": "…", "task_id": "…", "task_name": "guestbook", "run_id": "…", "status": "pending",
"summary": "Sign the guestbook with \"Hello from Example Inc.\"",
"target": "https://example.com/guestbook", "domain": "example.com",
"payload": {"steps": [{"op": "goto", "url": "https://example.com/guestbook"}, … ]},
"payload_sha256": "9c1e…", "screenshot_id": "…",
"requested_at": "…", "expires_at": "…", "decided_at": null, "decided_by": null, "reason": null,
"not_before": null, "executed_at": null, "result": null}Tras la fase de actuar, result es {"ok", "final_url", "error", "screenshot_id"}. Los pasos se describen en aprobaciones.
Errores
| Estado | code | Cuándo |
|---|---|---|
| 403 | feature_disabled | OpenWAF Tasks no está activado para la organización |
| 403 | forbidden | El rol no basta, o el miembro o el token están limitados a un cliente o una zona |
| 404 | not_found | No existe esa tarea, ejecución, artefacto o aprobación |
| 409 | payload_changed | El payload_sha256 enviado no es el de la aprobación |
| 409 | not_pending | La aprobación ya se decidió o caducó |
| 422 | invalid | Un campo incumple las reglas; field dice cuál |
CLI
openwaf-cloud ctl tasks … llama a la API anterior. Mira primeros pasos con la CLI.
La organización sale de --org o de OPENWAF_ORG. Los cambios enseñan lo que harán y preguntan antes de aplicarse (--yes no pregunta, --dry-run solo valida).
| Orden | Qué hace |
|---|---|
tasks list | Resumen y tareas |
tasks get <task> | Una tarea |
tasks create <task.json|-> --reason "…" | Crea una tarea a partir de un cuerpo JSON |
tasks update <task> <patch.json|-> --reason "…" | Cambia una tarea |
tasks delete <task> --reason "…" | Borra una tarea |
tasks run <task> --reason "…" | La ejecuta ahora |
tasks runs <task> [--limit n] | Ejecuciones de una tarea |
tasks run-get <run> | Una ejecución con sus aprobaciones y artefactos |
tasks cancel <run> --reason "…" | Cancela una ejecución |
tasks approvals [--status pending] [--task <task>] | Aprobaciones |
tasks approve <approval> --sha256 <hash> --reason "…" | Aprueba la carga exacta |
tasks reject <approval> --reason "…" | La rechaza |
Herramientas MCP
El servidor MCP de OpenWAF tiene 12 herramientas para OpenWAF Tasks. Las escrituras necesitan un reason y van en dos pasos: confirm=false solo comprueba y confirm=true aplica.
| Herramienta | Rol |
|---|---|
tasks_list | readonly |
tasks_get | readonly |
task_runs_list | readonly |
task_runs_get | readonly |
task_approvals_list | readonly |
tasks_create | admin |
tasks_update | admin |
tasks_delete | admin |
tasks_run | admin |
task_runs_cancel | admin |
task_approve | admin. El paso de comprobación enseña la carga exacta, su payload_sha256 y el id de la captura; el de aplicar necesita ese payload_sha256. |
task_reject | admin |
Un asistente puede prepararte una aprobación, pero lee tú los pasos antes de confirmarla.