Tasks
Tasks are user-owned commitments scoped to one of agentId / appId / workflowId. They can be one-shot (due_at) or recurring (daily / weekly / monthly / cron). The platform fires due tasks into workflows registered to handle them; this API lets you create, manage, and observe tasks programmatically.
All endpoints require authentication via X-API-Key header and the appropriate scope.
Scopes
| Scope | Endpoints |
|---|---|
tasks:read | GET /tasks, GET /tasks/:id, GET /tasks/:id/status |
tasks:write | POST /tasks, PUT /tasks/:id, DELETE /tasks/:id, POST /tasks/:id/complete, POST /tasks/:id/cancel, POST /tasks/:id/skip-next, POST /tasks/:id/end-recurrence, POST /tasks/:id/share, POST /tasks/:id/unshare, POST /tasks/:id/toggle-public |
Lifecycle
- One-shot tasks (no recurrence): status moves
open→fired→done/cancelled/failed. Terminal states cannot transition further. - Recurring tasks: status stays
openbetween fires. After each firedue_atadvances to the next slot,fire_countincrements, and a record is appended tofire_history(capped at 50 entries — older entries are dropped). POST /tasks/:id/completeon a recurring task closes the latestfire_historyentry (status: "done",completed_atset) and advancesdue_atto the next slot.skip_next: truecauses the next fire to advancedue_atwithout invoking any workflow, then resets tofalse.POST /tasks/:id/end-recurrenceis terminal — the recurring task moves to statusdoneandrecurrence_ended_atis set.
Task Object
{
"_id": "task_abc123",
"ownerId": "user_456",
"ownerName": "Alice Example",
"organizationId": "org_789",
"agentId": null,
"appId": null,
"workflowId": "wf_321",
"sharedWith": [],
"isPublic": false,
"description": "Run the weekly compliance report",
"subject_ref": {
"kind": "report",
"id": "rpt_001",
"app": "compliance-suite"
},
"created_by_agent": null,
"assigned_to_agent": "agent_compliance_bot",
"status": "open",
"due_at": "2026-05-23T09:00:00Z",
"fired_at": null,
"completed_at": null,
"failure_reason": null,
"notes": "Email the PDF to legal@example.com",
"recurrence": {
"kind": "weekly",
"time_of_day": "09:00",
"day_of_week": 6,
"day_of_month": null,
"cron": null,
"timezone": "America/Los_Angeles",
"until": null,
"max_fires": null
},
"next_due_at": "2026-05-23T09:00:00Z",
"last_fired_at": "2026-05-16T09:00:00Z",
"fire_count": 4,
"fire_history": [
{
"fired_at": "2026-05-16T09:00:00Z",
"completed_at": "2026-05-16T09:04:12Z",
"status": "done",
"execution_id": "exec_aaa111"
}
],
"recurrence_ended_at": null,
"skip_next": false,
"tags": ["compliance", "weekly"],
"createdAt": "2026-04-01T09:00:00Z",
"updatedAt": "2026-05-16T09:04:12Z"
}
GET /api/v1/tasks
List tasks the caller can read, with filters and pagination.
Scope: tasks:read
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | No | Filter by status: open / fired / done / failed / cancelled |
agentId | string | No | Narrow to tasks scoped to this agent |
appId | string | No | Narrow to tasks scoped to this app instance |
workflowId | string | No | Narrow to tasks scoped to this workflow |
assigned_to_agent | string | No | Narrow to tasks assigned to this agent |
tags | string | No | Comma-separated tag list (matches any) |
search | string | No | Full-text search on description and notes |
recurrence | string | No | Filter by recurrence kind: none / daily / weekly / monthly / cron |
dueBefore | string | No | ISO timestamp — only tasks with due_at ≤ this value |
dueAfter | string | No | ISO timestamp — only tasks with due_at ≥ this value |
limit | integer | No | Max results (default 50, max 200) |
offset | integer | No | Pagination offset |
Response 200 OK
{
"count": 12,
"limit": 50,
"offset": 0,
"tasks": [ /* Task objects */ ]
}
Example
curl -H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
"https://<your-instance>/api/v1/tasks?status=open&limit=20"
POST /api/v1/tasks
Create a new task. Pass recurrence to create a recurring task; omit it for a one-shot.
Scope: tasks:write
Request Body
{
"description": "Run the weekly compliance report",
"due_at": "2026-05-23T09:00:00Z",
"workflowId": "wf_321",
"assigned_to_agent": "agent_compliance_bot",
"subject_ref": {
"kind": "report",
"id": "rpt_001",
"app": "compliance-suite"
},
"notes": "Email the PDF to legal@example.com",
"tags": ["compliance", "weekly"],
"recurrence": {
"kind": "weekly",
"time_of_day": "09:00",
"day_of_week": 6,
"timezone": "America/Los_Angeles"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
description | string | Yes | One-line task description |
due_at | string | No | ISO timestamp the one-shot task is due (ignored for recurring tasks — first fire is computed from recurrence) |
agentId | string | No | Scope task to this agent (mutually exclusive with appId / workflowId) |
appId | string | No | Scope task to this app instance (mutually exclusive with agentId / workflowId) |
workflowId | string | No | Scope task to this workflow (mutually exclusive with agentId / appId) |
subject_ref | object | No | {kind, id, app?} — what the task is about |
created_by_agent | string | No | Agent that authored the task |
assigned_to_agent | string | No | Agent expected to handle fires |
notes | string | No | Free-form notes |
tags | string[] | No | Discoverability tags |
recurrence | object | No | Recurrence spec — see TaskRecurrence |
Response 201 Created
{ "taskId": "task_abc123" }
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "Run the weekly compliance report",
"workflowId": "wf_321",
"recurrence": { "kind": "weekly", "time_of_day": "09:00", "day_of_week": 6, "timezone": "America/Los_Angeles" }
}' \
https://<your-instance>/api/v1/tasks
Returns 400 validation-error if more than one of agentId / appId / workflowId is supplied, or if recurrence.kind is invalid.
GET /api/v1/tasks/:id
Get a single task by ID.
Scope: tasks:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
Returns the full Task object.
Example
curl -H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123
PUT /api/v1/tasks/:id
Update a task. Only the fields supplied are changed.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
description | string | No | One-line task description |
due_at | string | null | No | ISO timestamp the task is due (one-shot only) |
assigned_to_agent | string | null | No | Agent expected to handle fires |
subject_ref | object | No | {kind, id, app?} |
notes | string | null | No | Free-form notes |
tags | string[] | No | Discoverability tags |
recurrence | object | null | No | Replace the recurrence spec; pass null to convert to one-shot |
Response 200 OK
Returns the updated Task object.
Example
curl -X PUT \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "notes": "CC compliance@example.com as well" }' \
https://<your-instance>/api/v1/tasks/task_abc123
DELETE /api/v1/tasks/:id
Delete a task and its fire history. Irreversible.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 204 No Content
Example
curl -X DELETE \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123
GET /api/v1/tasks/:id/status
Focused status block — cheaper than a full object fetch when you only need lifecycle fields.
Scope: tasks:read
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
{
"taskId": "task_abc123",
"status": "open",
"due_at": "2026-05-23T09:00:00Z",
"next_due_at": "2026-05-23T09:00:00Z",
"last_fired_at": "2026-05-16T09:00:00Z",
"fired_at": null,
"completed_at": null,
"failure_reason": null,
"fire_count": 4,
"skip_next": false,
"recurrence_ended_at": null
}
Example
curl -H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123/status
POST /api/v1/tasks/:id/complete
Mark the task done. On a one-shot task this is terminal (status: "done"). On a recurring task this closes the latest fire_history entry and advances due_at to the next slot — the task stays open.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
execution_id | string | No | Execution that handled the fire — written into the closed fire_history entry |
notes | string | No | Free-form completion notes (appended to the task notes field) |
Response 200 OK
Returns the updated Task object.
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "execution_id": "exec_aaa111" }' \
https://<your-instance>/api/v1/tasks/task_abc123/complete
Returns 422 action-in-progress if the task is already in a terminal state.
POST /api/v1/tasks/:id/cancel
Mark the task as cancelled. Terminal for both one-shot and recurring tasks.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No | Free-form cancellation reason — written to failure_reason |
Response 200 OK
Returns the updated Task object (status: "cancelled").
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reason": "Compliance report no longer required" }' \
https://<your-instance>/api/v1/tasks/task_abc123/cancel
POST /api/v1/tasks/:id/skip-next
Skip the next scheduled fire of a recurring task. Sets skip_next: true — at the next scheduled slot, due_at advances without invoking any workflow, and skip_next resets to false.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
{ "skip_next": true }
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123/skip-next
Returns 400 validation-error if the task has no recurrence (one-shot tasks cannot be skipped).
POST /api/v1/tasks/:id/end-recurrence
Stop a recurring task. Terminal — moves the task to status: "done" and sets recurrence_ended_at to the server time of the call. No future fires will occur.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
Returns the updated Task object (status: "done", recurrence_ended_at set).
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123/end-recurrence
Returns 400 validation-error if the task has no recurrence.
POST /api/v1/tasks/:id/share
Share a task with another user. The user gains read access via sharedWith.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User to share with |
Response 200 OK
{ "success": true }
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "user_789" }' \
https://<your-instance>/api/v1/tasks/task_abc123/share
POST /api/v1/tasks/:id/unshare
Remove a user from sharedWith.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | User to unshare from |
Response 200 OK
{ "success": true }
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "user_789" }' \
https://<your-instance>/api/v1/tasks/task_abc123/unshare
POST /api/v1/tasks/:id/toggle-public
Flip whether the task is readable across the organization.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Response 200 OK
{ "isPublic": true }
Example
curl -X POST \
-H "X-API-Key: $STRONGLY_API_KEY" \
-H "Content-Type: application/json" \
https://<your-instance>/api/v1/tasks/task_abc123/toggle-public
PATCH /api/v1/tasks/:id/scope
Re-scope an existing task. Owner-only. See PATCH /api/v1/memory/:id/scope
for the full design rationale — same semantics apply: nested or flat
scope shapes, whitespace collapse to null, {"scope": {}} opt-out,
404 for cross-app rows.
Scope: tasks:write
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Task ID |
Request Body
{ "scope": { "appId": "app-instance-7" } }
Response 200 OK
{
"success": true,
"scope": { "agentId": null, "appId": "app-instance-7", "workflowId": null }
}
Schemas
TaskStatus
Enum string. Valid values:
| Value | Meaning |
|---|---|
open | Task is scheduled and waiting for its next fire. Default for recurring tasks between fires. |
fired | One-shot task has been dispatched to its workflow but has not yet completed. |
done | Terminal success state. For recurring tasks, set only by end-recurrence. |
failed | Terminal failure state. failure_reason is set. |
cancelled | Terminal — user-initiated cancellation. |
RecurrenceKind
Enum string. Valid values:
| Value | Description |
|---|---|
none | Not recurring (one-shot). Equivalent to omitting recurrence. |
daily | Fires every day at time_of_day (in timezone). |
weekly | Fires every day_of_week at time_of_day. |
monthly | Fires every day_of_month at time_of_day. |
cron | Fires per arbitrary cron expression in timezone. |
TaskRecurrence
{
"kind": "weekly",
"time_of_day": "09:00",
"day_of_week": 6,
"day_of_month": null,
"cron": null,
"timezone": "America/Los_Angeles",
"until": null,
"max_fires": null
}
| Field | Type | Required | Description |
|---|---|---|---|
kind | string | Yes | One of RecurrenceKind |
time_of_day | string | No | HH:MM 24-hour clock (used by daily / weekly / monthly) |
day_of_week | integer | No | 0–6 (Sunday=0). Required for weekly. |
day_of_month | integer | No | 1–31. Required for monthly. |
cron | string | No | Cron expression. Required for cron. |
timezone | string | No | IANA timezone (e.g. America/Los_Angeles); defaults to UTC. |
until | string | null | No | ISO timestamp at which recurrence stops automatically. |
max_fires | integer | null | No | Stop after N total fires. |
TaskSubjectRef
{
"kind": "report",
"id": "rpt_001",
"app": "compliance-suite"
}
| Field | Type | Required | Description |
|---|---|---|---|
kind | string | Yes | Free-form subject type (e.g. report, ticket, document) |
id | string | Yes | Subject identifier within its kind |
app | string | No | Originating app slug — used for cross-app references |
TaskFireRecord
{
"fired_at": "2026-05-16T09:00:00Z",
"completed_at": "2026-05-16T09:04:12Z",
"status": "done",
"execution_id": "exec_aaa111"
}
| Field | Type | Required | Description |
|---|---|---|---|
fired_at | string | Yes | ISO timestamp the workflow was dispatched |
completed_at | string | null | No | ISO timestamp the fire reached a terminal state |
status | string | Yes | done / failed / cancelled / skipped |
execution_id | string | null | No | Execution that handled the fire |
fire_history retains at most the 50 most recent entries — older entries are dropped as new fires append.