Base URL: http://{host}:{port}/api/v1
When auth.enabled is true, all endpoints except /health and POST /api/v1/auth/login require the Authorization: Bearer <token> header.
| Method | Path | Description | Status |
|---|---|---|---|
| POST | /api/v1/auth/login |
Login with username and password | 200 |
| POST | /api/v1/auth/logout |
Logout current session | 204 |
| GET | /api/v1/auth/me |
Validate token and get current user info | 200 |
| Method | Path | Description | Status |
|---|---|---|---|
| POST | /api/v1/tasks |
Create a task | 201 |
| GET | /api/v1/tasks |
List active tasks | 200 |
| GET | /api/v1/tasks/archived |
List archived tasks | 200 |
| GET | /api/v1/tasks/:id |
Get task by ID | 200 |
| PATCH | /api/v1/tasks/:id |
Update task (worker-only) | 200 |
| DELETE | /api/v1/tasks/:id |
Delete task | 204 |
| POST | /api/v1/tasks/:id/claim |
Claim task | 200 |
| POST | /api/v1/tasks/:id/release |
Release task | 200 |
| POST | /api/v1/tasks/:id/progress |
Report progress | 200 |
| POST | /api/v1/tasks/:id/complete |
Complete task (multipart) | 200 |
| POST | /api/v1/tasks/:id/cancel |
Cancel task | 200 |
| POST | /api/v1/tasks/:id/logs |
Append interaction logs | 204 |
| GET | /api/v1/tasks/:id/logs |
Get interaction logs | 200 |
| GET | /api/v1/tasks/:id/attachments |
List task attachments | 200 |
| GET | /api/v1/tasks/:id/attachments/:filename |
Download attachment | 200 |
| GET | /api/v1/tasks/:id/stream |
SSE stream for task status and logs | 200 |
| Method | Path | Description | Status |
|---|---|---|---|
| POST | /api/v1/clients/register |
Register client | 201 |
| GET | /api/v1/clients |
List all clients | 200 |
| GET | /api/v1/clients/:id |
Get client by ID | 200 |
| DELETE | /api/v1/clients/:id |
Unregister client | 204 |
| POST | /api/v1/clients/:id/heartbeat |
Send heartbeat | 204 |
| PATCH | /api/v1/clients/:id/agents |
Update agent list | 200 |
| POST | /api/v1/clients/:id/logs |
Append client logs | 204 |
| Method | Path | Description | Status |
|---|---|---|---|
| GET | /health |
Health check (no auth) | 200 |
Request body:
{
"username": "admin",
"password": "secret"
}Response (200):
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expiresAt": "2026-03-02T12:00:00.000Z"
}No request body. Returns 204 No Content.
Response (200) — session token:
{
"source": "session",
"role": "admin",
"username": "admin",
"expiresAt": "2026-03-02T12:00:00.000Z"
}Response (200) — static token:
{
"source": "static",
"role": "client"
}Accepts either JSON body or multipart/form-data (with data field as JSON and optional files for attachments).
Request body (JSON) — CreateTaskDTO:
{
"title": "Process dataset",
"description": "Run analysis on input.csv",
"tags": ["analysis", "batch"],
"priority": "normal",
"metadata": { "datasetId": "abc123" },
"callbackUrl": "https://example.com/webhook"
}Response (201):
{
"id": "0224d6a7-dee0-4a37-a70d-a803d4807890",
"title": "Process dataset",
"description": "Run analysis on input.csv",
"tags": ["analysis", "batch"],
"priority": "normal",
"status": "pending",
"metadata": { "datasetId": "abc123" },
"callbackUrl": "https://example.com/webhook",
"createdAt": "2026-03-01T10:00:00.000Z",
"updatedAt": "2026-03-01T10:00:00.000Z",
"attachments": []
}Query parameters: status, tag, page, limit
Query parameters: tag, search, page, limit
Returns full task object including claimedBy, progress, progressMessage, artifacts, etc.
Request body (UpdateTaskDTO):
{
"title": "Updated title",
"description": "Updated description",
"tags": ["new-tag"],
"priority": "high",
"metadata": {}
}Returns 204 No Content.
Request body (ClaimTaskDTO):
{
"clientId": "07d9de69-2114-43ec-9c70-79e22a0c0062",
"agentId": "agent-1"
}Request body (ReleaseTaskDTO):
{
"clientId": "07d9de69-2114-43ec-9c70-79e22a0c0062",
"reason": "Agent restarted"
}Request body (ProgressDTO):
{
"clientId": "07d9de69-2114-43ec-9c70-79e22a0c0062",
"agentId": "agent-1",
"progress": 75,
"message": "Processing batch 3 of 4",
"logs": ["Step 1 done", "Step 2 done"]
}Request: multipart/form-data with:
zip— artifact zip file (required)result—result.jsonfile (required)
Request body (CancelTaskDTO):
{
"clientId": "07d9de69-2114-43ec-9c70-79e22a0c0062",
"reason": "User requested cancellation"
}Response (200):
[
{
"originalName": "input.csv",
"mimeType": "text/csv",
"size": 1024
}
]Returns binary stream. Use Content-Disposition header for download filename.
Server-Sent Events stream. Query params: interval (poll interval ms, default 2000), logs (set to false to exclude logs).
Events: task, logs, done, error
Example:
const es = new EventSource('/api/v1/tasks/0224d6a7-dee0-4a37-a70d-a803d4807890/stream?interval=2000');
es.addEventListener('task', (e) => console.log(JSON.parse(e.data)));
es.addEventListener('logs', (e) => console.log(JSON.parse(e.data)));
es.addEventListener('done', (e) => { console.log(JSON.parse(e.data)); es.close(); });Query parameters: after (cursor for pagination)
Request body (AppendTaskLogsDTO):
{
"clientId": "07d9de69-2114-43ec-9c70-79e22a0c0062",
"agentId": "agent-1",
"entries": [
{
"id": "log-1",
"type": "step",
"timestamp": "2026-03-01T10:05:00.000Z",
"content": { "message": "Processing started" }
}
]
}Returns 204 No Content.
Request body (RegisterClientDTO):
{
"name": "Worker Node 1",
"host": "192.168.1.10",
"tags": ["prod", "gpu"],
"dispatchMode": "manager",
"agents": [
{
"id": "agent-1",
"type": "worker",
"command": "node worker.js",
"workDir": "/app",
"capabilities": ["python", "docker"]
}
]
}Response (201): Client object with id, name, host, status, agents, etc.
Request body (HeartbeatDTO):
{
"agents": [
{
"id": "agent-1",
"type": "worker",
"status": "busy",
"currentTaskId": "0224d6a7-dee0-4a37-a70d-a803d4807890",
"capabilities": ["python"]
}
]
}Returns 204 No Content.
Request body: Array of AgentInfo objects (same shape as in HeartbeatDTO).
Request body (AppendClientLogsDTO):
{
"entries": [
{
"id": "log-1",
"timestamp": "2026-03-01T10:05:00.000Z",
"level": "info",
"message": "Agent started"
}
]
}Returns 204 No Content.
Response (200):
{
"status": "ok",
"version": "0.0.1",
"authEnabled": true
}| DTO | Fields |
|---|---|
| CreateTaskDTO | title (string), description?, tags (string[]), priority?, metadata?, callbackUrl? |
| UpdateTaskDTO | title?, description?, tags?, priority?, metadata? |
| ClaimTaskDTO | clientId, agentId |
| ReleaseTaskDTO | clientId, reason? |
| ProgressDTO | clientId, agentId, progress (0–100), message?, logs? |
| CancelTaskDTO | clientId?, reason? |
| RegisterClientDTO | name, host, tags?, dispatchMode, agents (AgentRegistration[]) |
| HeartbeatDTO | agents? (AgentInfo[]) |
| CompleteTaskDTO | clientId, agentId, summary? (sent via multipart data field when applicable) |
| AppendTaskLogsDTO | clientId, agentId, entries (InteractionLogEntry[]) |
| AppendClientLogsDTO | entries (ClientLogEntry[]) |
| Code | HTTP | Description |
|---|---|---|
| TASK_NOT_FOUND | 404 | Task does not exist |
| TASK_ALREADY_CLAIMED | 409 | Task is already claimed by another worker |
| TASK_INVALID_TRANSITION | 400 | Invalid state transition for this operation |
| CLIENT_NOT_FOUND | 404 | Client does not exist |
| CLIENT_ALREADY_REGISTERED | 409 | Client already registered |
| CLIENT_OFFLINE | 400 | Client is offline |
| AGENT_NOT_FOUND | 404 | Agent does not exist |
| AGENT_BUSY | 409 | Agent is busy |
| UNAUTHORIZED | 401 | Missing or invalid token |
| FORBIDDEN | 403 | Insufficient permissions |
| VALIDATION_ERROR | 400 | Request validation failed |
| ARTIFACT_MISSING_ZIP | 400 | Complete request missing zip file |
| ARTIFACT_MISSING_RESULT | 400 | Complete request missing result.json |
| ARTIFACT_INVALID_JSON | 400 | result.json is invalid |
| ARTIFACT_HASH_MISMATCH | 400 | Artifact hash mismatch |
| QUEUE_FULL | 503 | Operation queue is full |
| AUTH_DISABLED | 404 | Authentication is not enabled |
| INTERNAL_ERROR | 500 | Unexpected server error |
All errors return:
{
"error": {
"code": "TASK_NOT_FOUND",
"message": "Task 0224d6a7-dee0-4a37-a70d-a803d4807890 not found",
"details": null
},
"timestamp": "2026-03-01T10:00:00.000Z"
}The details field is optional and may contain additional context.