Skip to main content

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

ScopeEndpoints
tasks:readGET /tasks, GET /tasks/:id, GET /tasks/:id/status
tasks:writePOST /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 openfireddone / cancelled / failed. Terminal states cannot transition further.
  • Recurring tasks: status stays open between fires. After each fire due_at advances to the next slot, fire_count increments, and a record is appended to fire_history (capped at 50 entries — older entries are dropped).
  • POST /tasks/:id/complete on a recurring task closes the latest fire_history entry (status: "done", completed_at set) and advances due_at to the next slot.
  • skip_next: true causes the next fire to advance due_at without invoking any workflow, then resets to false.
  • POST /tasks/:id/end-recurrence is terminal — the recurring task moves to status done and recurrence_ended_at is 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

ParameterTypeRequiredDescription
statusstringNoFilter by status: open / fired / done / failed / cancelled
agentIdstringNoNarrow to tasks scoped to this agent
appIdstringNoNarrow to tasks scoped to this app instance
workflowIdstringNoNarrow to tasks scoped to this workflow
assigned_to_agentstringNoNarrow to tasks assigned to this agent
tagsstringNoComma-separated tag list (matches any)
searchstringNoFull-text search on description and notes
recurrencestringNoFilter by recurrence kind: none / daily / weekly / monthly / cron
dueBeforestringNoISO timestamp — only tasks with due_at ≤ this value
dueAfterstringNoISO timestamp — only tasks with due_at ≥ this value
limitintegerNoMax results (default 50, max 200)
offsetintegerNoPagination 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"
}
}
FieldTypeRequiredDescription
descriptionstringYesOne-line task description
due_atstringNoISO timestamp the one-shot task is due (ignored for recurring tasks — first fire is computed from recurrence)
agentIdstringNoScope task to this agent (mutually exclusive with appId / workflowId)
appIdstringNoScope task to this app instance (mutually exclusive with agentId / workflowId)
workflowIdstringNoScope task to this workflow (mutually exclusive with agentId / appId)
subject_refobjectNo{kind, id, app?} — what the task is about
created_by_agentstringNoAgent that authored the task
assigned_to_agentstringNoAgent expected to handle fires
notesstringNoFree-form notes
tagsstring[]NoDiscoverability tags
recurrenceobjectNoRecurrence 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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask ID

Request Body

FieldTypeRequiredDescription
descriptionstringNoOne-line task description
due_atstring | nullNoISO timestamp the task is due (one-shot only)
assigned_to_agentstring | nullNoAgent expected to handle fires
subject_refobjectNo{kind, id, app?}
notesstring | nullNoFree-form notes
tagsstring[]NoDiscoverability tags
recurrenceobject | nullNoReplace 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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask ID

Request Body

FieldTypeRequiredDescription
execution_idstringNoExecution that handled the fire — written into the closed fire_history entry
notesstringNoFree-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

ParameterTypeRequiredDescription
idstringYesTask ID

Request Body

FieldTypeRequiredDescription
reasonstringNoFree-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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask ID

Request Body

FieldTypeRequiredDescription
userIdstringYesUser 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

ParameterTypeRequiredDescription
idstringYesTask ID

Request Body

FieldTypeRequiredDescription
userIdstringYesUser 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

ParameterTypeRequiredDescription
idstringYesTask 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

ParameterTypeRequiredDescription
idstringYesTask 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:

ValueMeaning
openTask is scheduled and waiting for its next fire. Default for recurring tasks between fires.
firedOne-shot task has been dispatched to its workflow but has not yet completed.
doneTerminal success state. For recurring tasks, set only by end-recurrence.
failedTerminal failure state. failure_reason is set.
cancelledTerminal — user-initiated cancellation.

RecurrenceKind

Enum string. Valid values:

ValueDescription
noneNot recurring (one-shot). Equivalent to omitting recurrence.
dailyFires every day at time_of_day (in timezone).
weeklyFires every day_of_week at time_of_day.
monthlyFires every day_of_month at time_of_day.
cronFires 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
}
FieldTypeRequiredDescription
kindstringYesOne of RecurrenceKind
time_of_daystringNoHH:MM 24-hour clock (used by daily / weekly / monthly)
day_of_weekintegerNo06 (Sunday=0). Required for weekly.
day_of_monthintegerNo131. Required for monthly.
cronstringNoCron expression. Required for cron.
timezonestringNoIANA timezone (e.g. America/Los_Angeles); defaults to UTC.
untilstring | nullNoISO timestamp at which recurrence stops automatically.
max_firesinteger | nullNoStop after N total fires.

TaskSubjectRef

{
"kind": "report",
"id": "rpt_001",
"app": "compliance-suite"
}
FieldTypeRequiredDescription
kindstringYesFree-form subject type (e.g. report, ticket, document)
idstringYesSubject identifier within its kind
appstringNoOriginating 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"
}
FieldTypeRequiredDescription
fired_atstringYesISO timestamp the workflow was dispatched
completed_atstring | nullNoISO timestamp the fire reached a terminal state
statusstringYesdone / failed / cancelled / skipped
execution_idstring | nullNoExecution that handled the fire

fire_history retains at most the 50 most recent entries — older entries are dropped as new fires append.