API Endpoints
Full reference for the daggle REST API. Base URL: http://localhost:{port}/api/v1.
System
GET /api/v1/health
Health check.
Response:
{
"status": "ok",
"version": "0.5.0",
"uptime_seconds": 3621
}curl -s http://localhost:8787/api/v1/health | jq .DAGs
GET /api/v1/dags
List all DAGs.
Response: flat array.
[
{
"name": "etl-daily",
"steps": 4,
"schedule": "0 3 * * *",
"last_status": "success",
"last_run": "2025-01-15T03:00:12Z"
}
]curl -s http://localhost:8787/api/v1/dags | jq .GET /api/v1/dags/{name}
Get details for a single DAG.
Response:
{
"name": "etl-daily",
"steps": 4,
"step_ids": ["fetch", "transform", "validate", "load"],
"schedule": "0 3 * * *",
"workdir": "/home/user/etl",
"r_version": "4.4.1",
"last_status": "success",
"last_run_id": "20250115T030012-abc12",
"last_run": "2025-01-15T03:00:12Z"
}curl -s http://localhost:8787/api/v1/dags/etl-daily | jq .POST /api/v1/dags/{name}/run
Trigger a new run. Returns immediately; poll status via the runs endpoint.
Request body (optional):
{
"params": {
"date": "2025-01-15",
"mode": "full"
}
}Response (201):
{
"run_id": "20250115T103000-abc12",
"status": "running"
}curl -s -X POST http://localhost:8787/api/v1/dags/etl-daily/run \
-H "Content-Type: application/json" \
-d '{"params": {"date": "2025-01-15"}}' | jq .GET /api/v1/dags/{name}/plan
Get the execution plan for a DAG, showing which steps are cached, outdated, or have no cache. Useful for dry-run previews before triggering.
Response: flat array.
[
{"step_id": "fetch", "status": "outdated", "reason": "input file changed"},
{"step_id": "transform", "status": "cached", "reason": "inputs unchanged since last run"},
{"step_id": "report", "status": "no-cache", "reason": "caching not enabled"}
]Each entry has:
step_id– Step identifier.status– One ofcached,outdated,no-cache.reason– Human-readable explanation.
curl -s http://localhost:8787/api/v1/dags/etl-daily/plan | jq .POST /api/v1/dags/{name}/validate
Validate a DAG definition without running it.
Response (200):
{
"valid": true,
"warnings": []
}curl -s -X POST http://localhost:8787/api/v1/dags/etl-daily/validate | jq .Runs
GET /api/v1/dags/{name}/runs
List all runs for a DAG.
Response: flat array.
[
{
"run_id": "20250115T030012-abc12",
"started": "2025-01-15T03:00:12Z",
"status": "success",
"duration_seconds": 47,
"dag_hash": "a1b2c3d4"
}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs | jq .GET /api/v1/dags/{name}/runs/{run_id}
Get full detail for a single run, including step statuses.
Use latest as run_id to get the most recent run.
Response:
{
"run_id": "20250115T030012-abc12",
"started": "2025-01-15T03:00:12Z",
"status": "success",
"duration_seconds": 47,
"dag_hash": "a1b2c3d4",
"steps": [
{"step_id": "fetch", "status": "success", "duration_seconds": 12},
{"step_id": "transform", "status": "success", "duration_seconds": 20},
{"step_id": "validate", "status": "success", "duration_seconds": 5},
{"step_id": "load", "status": "success", "duration_seconds": 10}
]
}curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest | jq .POST /api/v1/dags/{name}/runs/{run_id}/cancel
Cancel a running run.
Response (200):
{
"run_id": "20250115T103000-abc12",
"status": "cancelled"
}curl -s -X POST http://localhost:8787/api/v1/dags/etl-daily/runs/20250115T103000-abc12/cancel | jq .Steps
GET /api/v1/dags/{name}/runs/{run_id}/steps
List step statuses for a run.
Response: flat array.
[
{"step_id": "fetch", "status": "success", "duration_seconds": 12},
{"step_id": "transform", "status": "running", "duration_seconds": null},
{"step_id": "validate", "status": "pending", "duration_seconds": null}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/steps | jq .GET /api/v1/dags/{name}/runs/{run_id}/steps/{step_id}/log
Get stdout and stderr for a step.
Response:
{
"step_id": "fetch",
"stdout": "Fetching data from API...\nReceived 1432 rows.\n",
"stderr": ""
}curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/steps/fetch/log | jq .POST /api/v1/dags/{name}/runs/{run_id}/steps/{step_id}/approve
Approve a step that is waiting for approval.
Response (200):
{
"step_id": "load",
"status": "approved"
}curl -s -X POST http://localhost:8787/api/v1/dags/etl-daily/runs/latest/steps/load/approve | jq .POST /api/v1/dags/{name}/runs/{run_id}/steps/{step_id}/reject
Reject a step that is waiting for approval.
Response (200):
{
"step_id": "load",
"status": "rejected"
}curl -s -X POST http://localhost:8787/api/v1/dags/etl-daily/runs/latest/steps/load/reject | jq .Outputs
GET /api/v1/dags/{name}/runs/{run_id}/outputs
Get all outputs for a run.
Response: flat array.
[
{"step_id": "fetch", "key": "row_count", "value": "1432"},
{"step_id": "transform", "key": "output_path", "value": "/tmp/transformed.parquet"},
{"step_id": "validate", "key": "passed", "value": "true"}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/outputs | jq .Artifacts
GET /api/v1/dags/{name}/runs/{run_id}/artifacts
List all declared artifacts for a run. Each entry includes the file hash and size.
Response: flat array.
[
{
"step_id": "train",
"name": "model",
"path": "output/model.rds",
"abs_path": "/home/user/etl/output/model.rds",
"hash": "e3b0c44298fc1c149afbf4c8996fb924",
"size": 204800,
"format": "rds"
}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/artifacts | jq .Summaries
GET /api/v1/dags/{name}/runs/{run_id}/summaries
Get step summaries emitted via ::daggle-summary markers during a run.
Response: flat array.
[
{
"step_id": "transform",
"format": "markdown",
"content": "## Results\n\nProcessed **42** rows successfully."
}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/summaries | jq .Metadata
GET /api/v1/dags/{name}/runs/{run_id}/metadata
Get typed metadata entries emitted via ::daggle-meta markers during a run.
Response: flat array.
[
{"step_id": "train", "name": "row_count", "type": "numeric", "value": "1542"},
{"step_id": "train", "name": "model_desc", "type": "text", "value": "Linear regression"},
{"step_id": "train", "name": "residuals", "type": "image", "value": "output/residuals.png"}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/metadata | jq .Validations
GET /api/v1/dags/{name}/runs/{run_id}/validations
Get validation results emitted via ::daggle-validation markers during a run.
Response: flat array.
[
{"step_id": "validate", "name": "row_count", "status": "pass", "message": "Expected > 0, got 1542"},
{"step_id": "validate", "name": "schema", "status": "fail", "message": "Column 'date' expected date, got character"}
]curl -s http://localhost:8787/api/v1/dags/etl-daily/runs/latest/validations | jq .Run Comparison
GET /api/v1/dags/{name}/runs/compare?run1=X&run2=Y
Compare two runs side-by-side. Returns diffs for outputs, durations, and DAG metadata.
Query parameters:
run1– First run ID (required).run2– Second run ID (required).
Response:
{
"outputs_diff": [
{"step_id": "transform", "key": "row_count", "value1": "1432", "value2": "1501"}
],
"duration_diff": {
"run1_seconds": 47.2,
"run2_seconds": 52.8,
"diff_seconds": 5.6
},
"meta_diff": {
"dag_hash1": "a1b2c3d4e5f6",
"dag_hash2": "f6e5d4c3b2a1",
"changed": true
}
}curl -s "http://localhost:8787/api/v1/dags/etl-daily/runs/compare?run1=20250115T030012-abc12&run2=20250116T030015-def34" | jq .Maintenance
POST /api/v1/runs/cleanup
Remove old run data.
Request body:
{
"older_than": "30d"
}Response (200):
{
"removed": 42,
"freed_bytes": 10485760,
"freed": "10.0 MB"
}curl -s -X POST http://localhost:8787/api/v1/runs/cleanup \
-H "Content-Type: application/json" \
-d '{"older_than": "30d"}' | jq .Error responses
All errors return a JSON object with an error field:
{
"error": "DAG 'foo' not found"
}Status codes:
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created (new run triggered) |
| 400 | Bad request (invalid params, malformed body) |
| 404 | Resource not found |
| 409 | Conflict (e.g., cancelling an already-finished run) |
| 500 | Internal server error |