Skip to content

API

Base URL: http://localhost:8080 (configurable via server-config.yaml)

Task, job, and log endpoints do not require authentication unless the server is configured with an auth section. When ACL is configured, list endpoints (tasks, jobs, workspaces) are filtered based on user permissions. See Authorization for details.

GET /api/workspaces

Returns all configured workspaces with task and action counts.

Response:

[
{
"name": "default",
"tasks_count": 3,
"actions_count": 5,
"triggers_count": 1,
"revision": "abc123"
}
]
GET /api/workspaces/{ws}/tasks

Returns all tasks from the specified workspace.

ParameterDescription
wsWorkspace name

Response:

[
{
"name": "hello-world",
"workspace": "default",
"mode": "distributed",
"has_triggers": true
}
]

The folder field is included when set on the task. has_triggers is true when at least one enabled trigger targets this task.

GET /api/workspaces/{ws}/tasks/{name}
ParameterDescription
wsWorkspace name
nameTask name

Response:

{
"name": "hello-world",
"mode": "distributed",
"input": {
"name": { "type": "string", "default": "World" }
},
"flow": {
"say-hello": {
"action": "greet",
"input": { "name": "{{ input.name }}" }
}
},
"triggers": [
{
"name": "nightly",
"type": "scheduler",
"cron": "0 0 2 * * *",
"task": "hello-world",
"enabled": true,
"input": {},
"next_runs": ["2026-02-19T02:00:00+00:00"]
}
]
}

The triggers array contains all triggers targeting this task. Scheduler triggers include next_runs with the next 5 upcoming fire times.

POST /api/workspaces/{ws}/tasks/{name}/execute

Creates a new job for the given task.

ParameterDescription
wsWorkspace name
nameTask name

Request body:

{
"input": { "name": "World" }
}

Response:

{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
GET /api/workspaces/{ws}/triggers

Returns all triggers in the workspace with upcoming fire times for cron-based triggers.

Response:

[
{
"name": "nightly",
"type": "scheduler",
"cron": "0 0 2 * * *",
"task": "nightly-backup",
"enabled": true,
"input": { "env": "production" },
"next_runs": ["2026-02-19T02:00:00+00:00"]
}
]
GET /api/jobs
Query parameterDefaultDescription
workspaceFilter by workspace name
task_nameFilter by task name (requires workspace)
limit50Number of jobs to return
offset0Pagination offset

Response:

{
"items": [
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"workspace": "default",
"task_name": "hello-world",
"mode": "distributed",
"status": "completed",
"source_type": "api",
"source_id": null,
"revision": "abc123def456",
"created_at": "2025-02-10T12:00:00Z",
"started_at": "2025-02-10T12:00:01Z",
"completed_at": "2025-02-10T12:00:03Z"
}
],
"total": 1
}

Source types: "api", "user", "trigger", "webhook", "hook", "task"

Job statuses: pending, running, completed, failed, cancelled

GET /api/jobs/{id}

Returns job metadata and all steps with statuses.

ParameterDescription
idJob ID (UUID)

Response:

{
"job_id": "a1b2c3d4-...",
"workspace": "default",
"task_name": "hello-world",
"status": "completed",
"revision": "abc123def456",
"input": { "name": "World" },
"steps": [
{
"step_name": "say-hello",
"action_name": "greet",
"action_type": "script",
"runner": "local",
"input": { "name": "World" },
"output": { "greeting": "Hello World" },
"status": "completed",
"worker_id": "w1w2w3w4-...",
"started_at": "2025-02-10T12:00:01Z",
"completed_at": "2025-02-10T12:00:02Z",
"error_message": null
}
]
}

Step statuses: pending, ready, running, completed, failed, skipped, cancelled

POST /api/jobs/{id}/cancel

Cancels a pending or running job. Running steps are actively killed (processes terminated, containers stopped, pods deleted). Pending steps are marked as cancelled. Child jobs are recursively cancelled. Fires on_error hooks.

ParameterDescription
idJob ID (UUID)

Response (200):

{
"status": "cancelled"
}

Error responses:

StatusDescription
404Job not found
409Job is already in a terminal state (completed, failed, or cancelled)

CLI:

Terminal window
stroem cancel <job_id>
GET /api/jobs/{id}/logs

Returns combined log output from all steps in JSONL format.

Response:

{
"logs": "{\"ts\":\"...\",\"stream\":\"stdout\",\"step\":\"say-hello\",\"line\":\"Hello World\"}\n"
}
GET /api/jobs/{id}/steps/{step}/logs

Returns JSONL log output for a specific step. Use _server as the step name for server-side events.

GET /api/jobs/{id}/logs/stream

Opens a WebSocket connection for real-time log streaming. Sends existing content (backfill) on connect, then streams new chunks.

Terminal window
websocat ws://localhost:8080/api/jobs/JOB_ID/logs/stream
GET /api/users

Returns registered users with their authentication methods. Supports limit and offset query parameters. Response: { "items": [...], "total": N }.

GET /api/users/{id}

Returns a single user’s info including authentication methods and groups.

The following endpoints require admin privileges (is_admin: true). Non-admin users receive a 403 Forbidden response.

GET /api/users

Returns registered users with pagination.

Query parameterDefaultDescription
limit20Number of users to return
offset0Pagination offset

Response:

{
"items": [
{
"id": "user-uuid-...",
"email": "alice@example.com",
"is_admin": true,
"groups": ["devops", "admin"]
}
],
"total": 1
}
GET /api/users/{id}

Returns a single user’s info including admin flag and group memberships.

Response:

{
"id": "user-uuid-...",
"email": "alice@example.com",
"is_admin": true,
"groups": ["devops"]
}
PUT /api/users/{id}/admin

Grants or revokes admin privileges.

Request body:

{
"is_admin": true
}

Response (200):

{
"is_admin": true
}
PUT /api/users/{id}/groups

Updates the user’s group memberships.

Request body:

{
"groups": ["devops", "qa"]
}

Response (200):

{
"groups": ["devops", "qa"]
}
GET /api/groups

Returns all distinct group names in use.

Response:

["admin", "devops", "qa"]
GET /api/workers

Returns registered workers with status and tags. Supports limit and offset query parameters. Response: { "items": [...], "total": N }.

GET /api/workers/{id}

Returns a single worker’s info along with its recent steps (up to 50).

Response:

{
"steps": {
"items": [
{
"job_id": "...",
"workspace": "...",
"task_name": "...",
"job_status": "...",
"step_name": "...",
"action_type": "...",
"status": "...",
"started_at": "...",
"completed_at": "...",
"error_message": null
}
],
"total": 42
}
}

All endpoints return errors in a consistent format:

{
"error": "Description of what went wrong"
}
StatusDescription
400Bad request (invalid input, missing fields)
401Unauthorized (missing or invalid token)
404Not found (unknown task, job, or step)
409Conflict (e.g., cancelling an already-terminal job)
500Internal server error