A standalone task is a task raised on its own, with no template and no checklist behind it. It is the only kind of task you can create through the API — every other task exists because somebody ran a checklist from a template.
A standalone task lives at /v3/tasks/{taskKey}. A checklist task lives at /v3/checklists/{checklistKey}/tasks/{taskKey} and is documented on Checklist Tasks. The two kinds share almost nothing on the wire:
| Standalone task | Checklist task |
|---|
| Created by | POST /v3/tasks | Running a checklist |
| Address | /v3/tasks/{taskKey} | /v3/checklists/{checklistKey}/tasks/{taskKey} |
| Content | A description, one list of files and one list of sub-tasks | Whatever fields its template defines |
| Tags | Held against the task itself | Held against the checklist it is in |
| Who may edit or delete it | An Administrator, or the member who raised it if they have Task.Creator | Not deletable; edited through its template |
Each route family refuses the other kind's key. A checklist task's key sent to any route on this page is 404 TASK_NOT_FOUND, and a standalone task's key sent to a checklist task route is not found either.
Attached Tasks Are Still Standalone Tasks
A standalone task can be attached to a checklist. Attaching it sets the task's attachedChecklistKey and nothing else: the task keeps its key, stays at /v3/tasks/{taskKey} and is still read and written only through the routes on this page. Detaching it or moving it to another checklist does not change its key either. To find the tasks attached to a checklist, use List Attached Tasks, then work each one here.
Before You Start
-
Permissions. Every request acts as the member your API key acts as, and applies the permissions the app's own task dialogs apply. A key that acts as an Administrator or as the workspace needs none of the permissions below — though a key that acts as the workspace is not an Administrator, so it can update or delete only the tasks it raised itself. A key that acts as a Member:
- Reads a task — the task itself, its activity, comments, files, sub-tasks and tags — whenever the task is attached to nothing. A task attached to a checklist can be read only by a member who may see that checklist, under the rule on Checklists; anybody else is refused with
403 FORBIDDEN.
- Raises, updates and deletes a task only with Task.Creator. Updating or deleting it also needs the member to be the one who raised it (its
createdBy), or an Administrator.
- Attaches a task to a checklist — by raising it with
attachedChecklistKey, or by updating attachedChecklistKey to a different checklist — only with Task.Attacher and permission to run checklists from that checklist's template: Run and View or Run and View Assigned To in its Checklist Permissions. Taking a task off a checklist needs Task.Attacher alone. Sending the checklist the task is already on is not a change and asks for nothing.
- Comments on a task, attaches files, ticks sub-tasks, tags it and changes its status without any further permission.
Whoever the key acts as, a task can be attached only to a checklist whose template has Tasks Can Be Attached switched on. That is a setting on the template rather than a permission, so it refuses Administrators and workspace keys too, with 403 FORBIDDEN and field attachedChecklistKey. A task named in the path is looked up before anything is refused, so another workspace's task is still 404 TASK_NOT_FOUND, and an attachedChecklistKey naming another workspace's checklist is 404 CHECKLIST_NOT_FOUND rather than an attach refusal.
-
Workspace keys. The three snooze routes belong to a person and refuse a key that acts as the workspace with 403 API_KEY_ACTS_AS_WORKSPACE. See Authentication.
-
Fields. A standalone task's content is fixed: a description, files and sub-tasks. These correspond to the Text, File and Sub-Tasks controls in the app. The description is written by PATCH /v3/tasks/{taskKey}; the files and sub-tasks have routes of their own. Nothing on this page takes a field key.
-
Idempotency and rate limits. Every write on this page accepts an Idempotency-Key header — see Idempotency. Every route is charged to the standard rate-limit budget — see Rate Limits.
Endpoints
The MCP server has no tool for attaching a file, because the bytes would have to pass through the model's context as base64, and no tool for listing tags, because the tags are already on get_standalone_task. See Standalone Task Tools.
The Standalone Task Object
Returned by raise, get, update and the four status routes. It carries no comments, files or sub-tasks — each of those has its own route.
| Field | Type | Description |
|---|
key | string (GUID) | The task key. It never changes, including when the task is attached, moved or detached. |
name | string | The task's name. At most 100 characters. |
description | string | The description, as HTML. Absent when the task has none. |
attachedChecklistKey | string (GUID) | The key of the checklist the task is attached to. Absent when it is attached to nothing. Only the key is given — read the checklist with Get a Checklist if you need its name. |
dueDateTime | string (date-time) | When the task is due, in UTC. Absent when it has no due date. |
status | string | Incomplete, Complete or NotApplicable. Always present. Branch on this rather than on the two booleans. |
isComplete | boolean | true only when the task was completed. false for a task marked not applicable. |
isNotApplicable | boolean | true only when the task was marked not applicable. |
completedDateTime | string (date-time) | When it was completed. Absent when it has not been. |
completedBy | User reference | Who completed it. Absent when nobody has, or when that member has since been removed from the workspace. |
notApplicableDateTime | string (date-time) | When it was marked not applicable. Absent when it has not been. |
notApplicableBy | User reference | Who marked it not applicable, on the same terms as completedBy. |
assignees | array of Assignee | Everybody the task is assigned to. Empty when it is assigned to nobody. |
isAssignedExclusively | boolean | true when only the assignees (and Administrators) may complete the task. Reported, never accepted: a task raised through the API is always created with this set to true. |
createdBy | User reference | Who raised the task. This decides who may update or delete it. Absent when that member has since been removed from the workspace. |
tags | array of string | The task's tag names, ordered by name. Empty when it has none. |
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Incomplete",
"isComplete": false,
"isNotApplicable": false,
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Assignee
| Field | Type | Description |
|---|
id | integer | The member's or group's id. |
type | string | TeamMember or Group. Part of the identity: member 4 and group 4 are different assignees. |
name | string | The member's full name or the group's name. Absent for a member recorded with a surname and no first name. |
User Reference
| Field | Type | Description |
|---|
name | string | The member's full name. |
email | string | The member's email address. |
Naming Assignees and Mentions
Wherever this page accepts a person — assignees on raise and update, mentions on a comment — each entry names somebody in one of two ways:
| Form | Example | Notes |
|---|
| Type and id | { "type": "TeamMember", "id": 14 } | type is TeamMember or Group and is required with an id. Any name alongside an id is ignored. |
| Name | { "name": "James Okafor" } | A member's full name or email address, or a group's name, matched case-insensitively. |
A name that matches nobody, or that matches more than one member or group, is refused with 400 VALIDATION_ERROR. The message for an ambiguous name lists the candidates by type and id so that you can pick one. An email address is always unique, so use it when two members share a name. An id the workspace cannot assign — another workspace's member, a deactivated member or a group that does not exist — is also refused rather than silently dropped.
Raise a Task
Creates a standalone task, optionally attached to a checklist. The task is recorded as raised by the member your API key acts as, which makes that member one of the people who may later update or delete it.
Parameters
This endpoint takes no parameters.
Request Body
{
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"assignees": [
{ "name": "james.okafor@acme.example" }
],
"tags": ["urgent", "q3-audit"]
}
| Field | Type | Required | Description |
|---|
name | string | Yes | The task's name. Trimmed; blank is refused, and so is anything over 100 characters (it is refused rather than cut short). |
description | string | No | The description, as HTML. Leave it out, or send null or an empty string, for a task with no description. |
attachedChecklistKey | string (GUID) | No | The checklist to attach the task to. It must be one of this workspace's checklists. Leave it out, or send null or an empty string, to attach it to nothing. |
dueDateTime | string (date-time) | No | When the task is due. A value without an offset is read as UTC. Must be on or after 1 January 1753. |
assignees | array | No | Who to assign the task to, each entry named as described in Naming Assignees and Mentions. Duplicates are collapsed. |
tags | array of string | No | Tag names to put on the task. Each is trimmed and at most 100 characters; duplicates are collapsed case-insensitively; at most 25 after that. A name the workspace has not used before creates the tag. An empty array is the same as leaving it out. |
The body has no field for sub-tasks or files. Add those after the task exists, with Add Sub-Tasks and Attach a File. There is no isAssignedExclusively field either: a task raised here is always assigned exclusively.
Example
POST https://api.checkflow.io/v3/tasks
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"assignees": [
{ "name": "james.okafor@acme.example" }
],
"tags": ["urgent", "q3-audit"]
}
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Incomplete",
"isComplete": false,
"isNotApplicable": false,
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
201 Created | — | The task was raised. The body is a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | The body is missing or is not valid JSON; name is blank or over 100 characters (field: name); attachedChecklistKey is not a GUID (field: attachedChecklistKey); dueDateTime is before 1753 (field: dueDateTime); an assignee names nobody, more than one, or somebody the workspace cannot assign (field: assignees, or the entry, such as assignees[0].name); more than 25 tags or a tag over 100 characters (field: tags). |
403 Forbidden | FORBIDDEN | The key acts as a Member without Task.Creator; attachedChecklistKey was sent and the Member lacks Task.Attacher or permission to run the checklist's template; or the checklist's template has Tasks Can Be Attached switched off, which refuses every key (field: attachedChecklistKey). |
404 Not Found | CHECKLIST_NOT_FOUND | attachedChecklistKey names no checklist in this workspace. |
Notes
- Everybody in
assignees is notified of the new assignment, as they are when a task is assigned in the app.
- If the task is attached to a checklist, that checklist's completion is recalculated: a finished checklist is reopened by a new, incomplete task.
- The response always has
status Incomplete. There is no way to raise a task in any other state.
Get a Standalone Task
Returns one standalone task.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97
X-API-KEY: your-api-key-here
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Complete",
"isComplete": true,
"isNotApplicable": false,
"completedDateTime": "2026-09-29T14:12:05Z",
"completedBy": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The body is a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID (field: taskKey). |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. This includes the key of a checklist task. |
Update a Standalone Task
Changes a standalone task's name, description, attachment, due date or assignees. Use it to attach a task to a checklist, move it to another one or detach it.
PATCH /v3/tasks/{taskKey}
This is a partial update, not a JSON merge patch: the body is a flat object, and for each of the five fields a property you leave out is left alone while a property you send as null is cleared. A body naming none of the five fields is refused — including one whose only property is misspelled. See Partial Updates with PATCH.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"attachedChecklistKey": null,
"dueDateTime": "2026-10-08T09:00:00Z",
"assignees": [
{ "type": "TeamMember", "id": 15 },
{ "name": "Finance Team" }
]
}
| Field | Type | Required | Description |
|---|
name | string | No | The new name. At most 100 characters. Cannot be cleared — null or blank is refused. |
description | string | No | The new description, as HTML. null or an empty string removes the description. |
attachedChecklistKey | string (GUID) | No | The checklist to attach the task to, which must be one of this workspace's. null or an empty string detaches it. |
dueDateTime | string (date-time) | No | The new due date, on or after 1 January 1753. null clears it. |
assignees | array | No | Who the task should be assigned to afterwards — a replacement, not an addition. Each entry is named as described in Naming Assignees and Mentions. An empty array (or null) unassigns everybody. |
At least one field is required. Tags are not changed here — use Tag a Task and Untag a Task. Sub-tasks and files are not touched by an update.
Example
PATCH https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"attachedChecklistKey": null,
"dueDateTime": "2026-10-08T09:00:00Z",
"assignees": [
{ "type": "TeamMember", "id": 15 },
{ "name": "Finance Team" }
]
}
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"dueDateTime": "2026-10-08T09:00:00Z",
"status": "Incomplete",
"isComplete": false,
"isNotApplicable": false,
"assignees": [
{ "id": 15, "type": "TeamMember", "name": "Priya Patel" },
{ "id": 3, "type": "Group", "name": "Finance Team" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The body is the task as it now reads, a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; the body is not a JSON object or names none of the five fields; name is blank or over 100 characters (field: name); attachedChecklistKey is not a GUID; dueDateTime is before 1753 (field: dueDateTime); an assignee names nobody, more than one, or somebody the workspace cannot assign. |
403 Forbidden | FORBIDDEN | The member the key acts as is neither an Administrator nor the member who raised the task; the key acts as a Member without Task.Creator; attachedChecklistKey changes and the Member lacks Task.Attacher or, for a checklist, permission to run its template; or the checklist's template has Tasks Can Be Attached switched off, which refuses every key (field: attachedChecklistKey). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | CHECKLIST_NOT_FOUND | attachedChecklistKey names no checklist in this workspace. |
Notes
- When the attachment changes, the completion of both the checklist the task left and the one it joined is recalculated. A checklist that was waiting only on this task may now be finished, and a finished one may be reopened.
- When
assignees changes the set of people on the task, the new assignment is announced as it is in the app. Sending the same assignees the task already has announces nothing, so re-saving a task does not notify everybody again. Nobody is notified of being unassigned.
- The tags survive attaching, moving and detaching, because a standalone task's tags are held against the task rather than the checklist.
Delete a Standalone Task
Permanently deletes a standalone task, along with its comments, files and tags.
DELETE /v3/tasks/{taskKey}
Deleting a standalone task cannot be undone. There is no archive or recycle bin for standalone tasks, and the task's comments, files and tag assignments are deleted with it.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97
X-API-KEY: your-api-key-here
Responds 204 No Content with no body.
Responses
| Status | Code | When |
|---|
204 No Content | — | The task was deleted. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | FORBIDDEN | The key acts as a Member without Task.Creator, or the member the key acts as is neither an Administrator nor the member who raised the task. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key — including one that has already been deleted. |
Notes
- If the task was attached to a checklist, that checklist's completion is recalculated afterwards: a checklist that was waiting only on this task may now be finished.
- Deleting a tag's last assignment removes the tag from the workspace, as Untag a Task does.
Complete a Standalone Task
Marks the task complete. The route names the state rather than a transition, so completing a task that is already complete writes nothing and still answers 200.
POST /v3/tasks/{taskKey}/complete
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
This endpoint takes no request body.
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/complete
X-API-KEY: your-api-key-here
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"description": "<p>The supplier has not returned a signed W-9. Chase before payment is released.</p>",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Complete",
"isComplete": true,
"isNotApplicable": false,
"completedDateTime": "2026-09-29T14:12:05Z",
"completedBy": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The body is the task as it now stands, a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
409 Conflict | CONFLICT | The task cannot be completed yet: a sub-task is still unticked, or the task is assigned exclusively and the member the key acts as is neither one of its assignees nor an Administrator. The message says which. |
Notes
- A task's sub-tasks must all be ticked first. Read them with List Sub-Tasks and tick each with Tick a Sub-Task.
- A completion that changes the task fires the
task_completed webhook, records an activity entry and sends an in-app notification to the task's assignees and the workspace's Administrators (not to the member who completed it). A repeated call that changes nothing does none of these.
- An exclusively assigned task with no assignees can be completed by anybody.
Uncomplete a Standalone Task
Returns a completed task to Incomplete. It clears completion only: a task that is not complete — including one marked not applicable — is left exactly as it is and the call still answers 200. Use Clear Not Applicable for that.
DELETE /v3/tasks/{taskKey}/complete
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/complete
X-API-KEY: your-api-key-here
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Incomplete",
"isComplete": false,
"isNotApplicable": false,
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The body is the task as it now stands, a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
- Uncompleting is never refused for missing content or exclusive assignment.
- A change records an activity entry and sends the same in-app notification as completing.
Mark a Standalone Task Not Applicable
Marks the task not applicable: it does not need doing. It then reads as NotApplicable, isComplete stays false and nobody is credited with completing it. Repeating the call writes nothing and still answers 200.
POST /v3/tasks/{taskKey}/not-applicable
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
This endpoint takes no request body.
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/not-applicable
X-API-KEY: your-api-key-here
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "NotApplicable",
"isComplete": false,
"isNotApplicable": true,
"completedDateTime": "2026-09-29T14:20:41Z",
"notApplicableDateTime": "2026-09-29T14:20:41Z",
"notApplicableBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
A task marked not applicable also carries a completion time underneath, which is why completedDateTime can appear alongside status NotApplicable. Read status, not completedDateTime, to decide whether a task was done.
Responses
| Status | Code | When |
|---|
200 OK | — | The body is the task as it now stands, a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
- Unlike completing, marking a task not applicable is never refused for unticked sub-tasks.
- A change records an activity entry and sends an in-app notification to the task's assignees and the workspace's Administrators.
Clear Not Applicable
Returns a not-applicable task to Incomplete. It clears not applicable only: a task that is not marked not applicable — including a completed one — is left exactly as it is and the call still answers 200. Use Uncomplete a Standalone Task for that.
DELETE /v3/tasks/{taskKey}/not-applicable
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/not-applicable
X-API-KEY: your-api-key-here
{
"key": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"name": "Chase missing W-9 from supplier",
"attachedChecklistKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"dueDateTime": "2026-10-01T09:00:00Z",
"status": "Incomplete",
"isComplete": false,
"isNotApplicable": false,
"assignees": [
{ "id": 14, "type": "TeamMember", "name": "James Okafor" }
],
"isAssignedExclusively": true,
"createdBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" },
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The body is the task as it now stands, a Standalone Task object. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Get a Standalone Task's Activity
Returns what has happened to the task, most recent first — the same entries, in the same shape, as a checklist task's history. The feed is filtered by the task rather than by a checklist, so a task that has been attached and detached keeps its whole history.
GET /v3/tasks/{taskKey}/activity
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
sort | query | string | No | occurredAt, occurredAt:asc or occurredAt:desc. Default occurredAt:desc. Any other value is refused. |
pageSize | query | integer | No | Entries per page, 1–100. Default 50. A value outside that range, or one that is not a number, is replaced by 50 rather than refused. |
after | query | string | No | The nextCursor from the previous page. Send the same sort it was issued under. You can change pageSize between pages. |
See Pagination for how cursors work.
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/activity?pageSize=2
X-API-KEY: your-api-key-here
{
"items": [
{
"occurredAt": "2026-09-29T14:12:05Z",
"actor": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"description": "completed task 'Chase missing W-9 from supplier'",
"taskKey": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"taskName": "Chase missing W-9 from supplier"
},
{
"occurredAt": "2026-09-28T10:03:17Z",
"actor": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"description": "uncompleted task 'Chase missing W-9 from supplier'",
"taskKey": "7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97",
"taskName": "Chase missing W-9 from supplier"
}
],
"nextCursor": "eyJ2IjoxLCJzIjoib2NjdXJyZWRBdDpkZXNjIn0",
"hasMore": true,
"total": 6
}
Each entry has these fields:
| Field | Type | Description |
|---|
occurredAt | string (date-time) | When it happened, in UTC. |
actor | User reference | Who did it. A member who has since left reads as Unknown User; system actors such as API Service have no email. |
description | string | What happened, as a sentence. Names are resolved when the feed is read, so a renamed task reads under its current name throughout. |
taskKey | string (GUID) | The task the entry is about. |
taskName | string | The task's current name. Absent when it has been deleted. |
fieldKey | string (GUID) | The field the entry is about, when it is about one. |
fieldName | string | That field's current label, when there is one. |
dateTimeValue | string (date-time) | The value a date field was set to, for entries that record one. |
There is no event type field: activity is recorded as prose. total counts the whole feed, not the page.
Responses
| Status | Code | When |
|---|
200 OK | — | A page of activity entries. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; sort is not one of the allowed values (field: sort); after is unreadable or came from a different feed or sort (field: after). |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
Most entries are written asynchronously, a second or two after the event. Do not poll this feed to confirm a write you have just made — the response to the write is the confirmation.
Returns the task's comments, oldest first. This is the only way to read them: the task object carries no comments, and the checklist routes do not return a standalone task's comments even when it is attached.
GET /v3/tasks/{taskKey}/comments
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
The list is not paged.
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/comments
X-API-KEY: your-api-key-here
{
"comments": [
{
"id": 48213,
"text": "@Priya Patel can you confirm the supplier tax ID before I chase?",
"html": "<p><span contenteditable=\"false\"><a class=\"mention-link\" data-id=\"15\" data-assignable-type=\"1\">@Priya Patel</a></span> can you confirm the supplier tax ID before I chase?</p>",
"createdBy": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"createdDateTime": "2026-09-28T09:41:12Z",
"mentions": [
{ "id": 15, "type": "TeamMember", "name": "Priya Patel" }
]
},
{
"id": 48220,
"text": "Signed W-9 attached.",
"html": "<p>Signed W-9 attached.</p>",
"createdBy": { "name": "Priya Patel", "email": "priya.patel@acme.example" },
"createdDateTime": "2026-09-28T15:07:55Z",
"attachment": {
"name": "w9-signed.pdf",
"contentType": "application/pdf",
"url": "https://example.blob.core.windows.net/files/5d0e7a3c-w9-signed.pdf"
},
"mentions": []
}
]
}
Each comment has these fields:
| Field | Type | Description |
|---|
id | integer | The comment's id, used to delete it. |
text | string | What the comment says, with the markup removed. Read this unless you need the markup. |
html | string | The comment as stored and as the app renders it. Absent for a comment that is only an attachment. Comments written before v3 were stored as the browser sent them, so do not re-render this markup without sanitising it. |
createdBy | User reference | Who wrote it. An author who has left the workspace keeps their name and loses their email. |
createdDateTime | string (date-time) | When it was written. |
attachment | object | The file attached to the comment, with name, contentType and url. Absent when there is none. |
mentions | array of Assignee | Everybody the comment mentions, in order, each listed once. name is the name the mention was written against, not necessarily today's name. |
An attachment's url is not protected by your API key. Anybody holding the address can download the file, so treat the URL as a secret.
Responses
| Status | Code | When |
|---|
200 OK | — | The task's comments, oldest first. An empty comments array when there are none. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Adds a comment to the task, written as the member your API key acts as. Comments cannot be edited afterwards — a comment either stays or is deleted whole.
POST /v3/tasks/{taskKey}/comments
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"text": "Priya Patel can you confirm the supplier tax ID before I chase?",
"mentions": [
{ "name": "Priya Patel" }
],
"assignMentioned": false
}
| Field | Type | Required | Description |
|---|
text | string | No | What to say, as plain text. It is escaped and wrapped into paragraphs: a blank line starts a paragraph, a single newline is a line break and anything that looks like markup is shown as text. Use this unless you genuinely have HTML. |
html | string | No | What to say, as HTML. Only paragraphs, line breaks, headings, lists, tables, basic emphasis and links to http, https or mailto are kept; other elements are dropped and their text kept. Send text or html, not both. |
mentions | array | No | People or groups to mention, each named as described in Naming Assignees and Mentions. Each mention replaces the first place the comment already says that name (with or without @); anybody the comment never names is mentioned at the end. |
assignMentioned | boolean | No | Whether mentioning somebody on an exclusively assigned task also assigns them to it. Default true. Send false when you are informing somebody rather than asking them to act. |
attachment | object | No | A file to attach to the comment. |
attachment.name | string | With attachment | The file name. |
attachment.content | string | With attachment | The file's bytes, base64 encoded. At most 32 MB once decoded. |
attachment.contentType | string | No | The file's media type. Default application/octet-stream. |
A comment needs something in it: text, HTML that survives the allow-list, a mention or an attachment. A comment that is only an attachment, or only mentions, is allowed.
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/comments
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"text": "Priya Patel can you confirm the supplier tax ID before I chase?",
"mentions": [
{ "name": "Priya Patel" }
],
"assignMentioned": false
}
{
"comment": {
"id": 48213,
"text": "@Priya Patel can you confirm the supplier tax ID before I chase?",
"html": "<p><span contenteditable=\"false\"><a class=\"mention-link\" data-id=\"15\" data-assignable-type=\"1\">@Priya Patel</a></span> can you confirm the supplier tax ID before I chase?</p>",
"createdBy": { "name": "James Okafor", "email": "james.okafor@acme.example" },
"createdDateTime": "2026-09-28T09:41:12Z",
"mentions": [
{ "id": 15, "type": "TeamMember", "name": "Priya Patel" }
]
},
"assignedMentioned": []
}
| Field | Type | Description |
|---|
comment | object | The comment as stored, in the shape List Comments returns. |
assignedMentioned | array of Assignee | Anybody the comment's mentions added to the task's assignees. Empty unless the task is assigned exclusively and assignMentioned was not false. |
Responses
| Status | Code | When |
|---|
201 Created | — | The comment was added. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; both text and html were sent (field: html); the comment has nothing in it (field: text) or its HTML is empty once sanitised (field: html); a mention names nobody, more than one or an id the workspace does not have (field: such as mentions[0].name); the attachment has no name (field: attachment.name), is not base64 or is over 32 MB (field: attachment.content). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
- Everybody assigned to the task, and everybody mentioned, is notified by email and Slack, as they are for a comment left in the app.
- On an exclusively assigned task, a mentioned person who is not yet an assignee is added to the assignees unless you send
assignMentioned: false. They are notified either way.
Permanently deletes one comment, with any file attached to it. Only the comment's author or an Administrator may delete it — raising the task grants nothing here.
DELETE /v3/tasks/{taskKey}/comments/{commentId}
Deleting a comment cannot be undone. Its attachment is deleted from storage with it.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
commentId | path | integer | Yes | The comment's id, from List Comments. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/comments/48213
X-API-KEY: your-api-key-here
Responds 204 No Content with no body.
Responses
| Status | Code | When |
|---|
204 No Content | — | The comment was deleted. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID, or commentId is not a positive whole number (field: commentId). |
403 Forbidden | FORBIDDEN | The member the key acts as did not write the comment and is not an Administrator. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | COMMENT_NOT_FOUND | There is no comment with that id on this task — including one on a different task. |
List Files
Returns the files attached to the task. A standalone task has exactly one place for files, so the route takes no field key and the response is just the list.
GET /v3/tasks/{taskKey}/files
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/files
X-API-KEY: your-api-key-here
{
"files": [
{
"id": 90417,
"name": "supplier-remittance.pdf",
"contentType": "application/pdf",
"url": "https://example.blob.core.windows.net/files/8a4f2c61-supplier-remittance.pdf",
"description": "Remittance advice from the supplier portal",
"uploadedDateTime": "2026-09-27T16:22:09Z",
"uploadedBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" }
}
]
}
Each file has these fields:
| Field | Type | Description |
|---|
id | integer | The file's id, used to remove it. |
name | string | The name it was uploaded under. Not unique — the same name can appear twice. |
contentType | string | The media type recorded at upload. Not checked against the bytes. |
url | string | Where the bytes are stored. |
description | string | The note kept with the file. Absent when there is none. |
uploadedDateTime | string (date-time) | When it was uploaded. |
uploadedBy | User reference | Who uploaded it. Absent when they have since left the workspace. |
A file's url is not protected by your API key. Anybody holding the address can download the file, so treat the URL as a secret.
Responses
| Status | Code | When |
|---|
200 OK | — | The task's files. An empty files array when there are none. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Attach a File
Attaches one file to the task. The file travels base64 encoded inside a JSON body, not as a multipart upload.
POST /v3/tasks/{taskKey}/files
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"name": "supplier-remittance.pdf",
"content": "JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c+PgplbmRvYmoK",
"contentType": "application/pdf",
"description": "Remittance advice from the supplier portal"
}
| Field | Type | Required | Description |
|---|
name | string | Yes | The file name to list it under. Trimmed; blank is refused. Not checked for uniqueness. |
content | string | Yes | The file's bytes, base64 encoded. At most 32 MB once decoded. |
contentType | string | No | The media type. Default application/octet-stream. |
description | string | No | A note to keep with the file. |
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/files
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"name": "supplier-remittance.pdf",
"content": "JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2c+PgplbmRvYmoK",
"contentType": "application/pdf",
"description": "Remittance advice from the supplier portal"
}
{
"file": {
"id": 90417,
"name": "supplier-remittance.pdf",
"contentType": "application/pdf",
"url": "https://example.blob.core.windows.net/files/8a4f2c61-supplier-remittance.pdf",
"description": "Remittance advice from the supplier portal",
"uploadedDateTime": "2026-09-27T16:22:09Z",
"uploadedBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" }
},
"files": [
{
"id": 90417,
"name": "supplier-remittance.pdf",
"contentType": "application/pdf",
"url": "https://example.blob.core.windows.net/files/8a4f2c61-supplier-remittance.pdf",
"description": "Remittance advice from the supplier portal",
"uploadedDateTime": "2026-09-27T16:22:09Z",
"uploadedBy": { "name": "Sarah Chen", "email": "sarah.chen@acme.example" }
}
]
}
files is every file now on the task, in the shape List Files returns, and file is the one this call added — so you can take its id without comparing lists.
Responses
| Status | Code | When |
|---|
201 Created | — | The file was attached. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; name is missing or blank (field: name); content is missing, not base64 or over 32 MB (field: content). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
- There is no limit on the number of files. Uploading the same name twice leaves two files with different ids.
- The upload is recorded in the task's activity.
Remove a File
Removes one file from the task and, when no other file row points at the same stored bytes, deletes the bytes from storage. This is the only way to remove a file from a standalone task — the app's task editor can add files but not remove them.
DELETE /v3/tasks/{taskKey}/files/{fileId}
Removing a file deletes the stored bytes when this was their last use, which is the normal case on a standalone task. It cannot be undone.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
fileId | path | integer | Yes | The file's id, from List Files. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/files/90417
X-API-KEY: your-api-key-here
{
"blobDeleted": true,
"files": []
}
| Field | Type | Description |
|---|
files | array | The files left on the task, in the shape List Files returns. |
blobDeleted | boolean | true when the stored bytes were deleted as well. |
Responses
| Status | Code | When |
|---|
200 OK | — | The file was removed. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID, or fileId is not a positive whole number (field: fileId). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | FILE_NOT_FOUND | There is no file with that id on this task. |
Notes
The removal is recorded in the task's activity.
Get a Standalone Task's Snooze
Says whether the task is snoozed for the member your API key acts as, and until when. A snooze is private to one person: it hides the task from that person's Tasks grid and changes nothing anybody else sees, so keys acting as different members get different answers.
GET /v3/tasks/{taskKey}/snooze
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/snooze
X-API-KEY: your-api-key-here
{
"isSnoozed": true,
"snoozedUntil": "2026-10-05T08:00:00Z"
}
| Field | Type | Description |
|---|
isSnoozed | boolean | Whether the task is hidden from this member's Tasks grid right now. |
snoozedUntil | string (date-time) | When the snooze runs out, in UTC. Absent when this member has never snoozed the task. Still reported after it has run out — with isSnoozed false — so you can tell an expired snooze from none. |
Responses
| Status | Code | When |
|---|
200 OK | — | The snooze state for the acting member. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | API_KEY_ACTS_AS_WORKSPACE | The key acts as the workspace rather than a member. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Snooze a Standalone Task
Hides the task from the acting member's Tasks grid until the date you give. Sending a date again replaces it. To snooze several tasks at once, see My Work.
PUT /v3/tasks/{taskKey}/snooze
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"snoozedUntil": "2026-10-05T08:00:00Z"
}
| Field | Type | Required | Description |
|---|
snoozedUntil | string (date-time) | Yes | When the snooze should run out, in UTC. Must be in the future. null is refused — use End a Snooze to clear one. |
Example
PUT https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/snooze
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"snoozedUntil": "2026-10-05T08:00:00Z"
}
{
"isSnoozed": true,
"snoozedUntil": "2026-10-05T08:00:00Z"
}
Responses
| Status | Code | When |
|---|
200 OK | — | The task is snoozed for the acting member. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; snoozedUntil is missing, unreadable or not in the future (field: snoozedUntil). |
403 Forbidden | API_KEY_ACTS_AS_WORKSPACE | The key acts as the workspace rather than a member. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
A snooze records no activity entry, sends no notification and fires no webhook. The task stays on everybody else's grid.
End a Snooze
Returns the task to the acting member's Tasks grid. A task that was not snoozed, or whose snooze has already run out, is left as it is and the call still answers 200.
DELETE /v3/tasks/{taskKey}/snooze
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/snooze
X-API-KEY: your-api-key-here
Responses
| Status | Code | When |
|---|
200 OK | — | The task is no longer snoozed for the acting member. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | API_KEY_ACTS_AS_WORKSPACE | The key acts as the workspace rather than a member. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
The Sub-Tasks Object
Returned by every sub-task route. A standalone task has at most one list of sub-tasks, so no route takes a field key.
| Field | Type | Description |
|---|
isRequired | boolean | Whether every item must be ticked before the task can be completed. true whenever the task has sub-tasks; false for a task with none. |
items | array | The sub-tasks, in the order they are meant to be worked. Empty when there are none. |
items[].key | string (GUID) | The sub-task key. It stays the same through rewording, moving, ticking and unticking. |
items[].text | string | What the item says. |
items[].isChecked | boolean | Whether it has been ticked. |
items[].position | integer | Where it sits in the list, counting from 1. Positions are always contiguous from 1, so a position you read can be sent back to Reword or Move a Sub-Task. |
{
"isRequired": true,
"items": [
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 1 },
{ "key": "e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28", "text": "Email supplier for signed W-9", "isChecked": false, "position": 2 },
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload W-9 to the vendor file", "isChecked": false, "position": 3 }
]
}
List Sub-Tasks
Returns the task's sub-tasks. Read these before completing a task: Complete a Standalone Task is refused while any item is unticked.
GET /v3/tasks/{taskKey}/sub-tasks
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks
X-API-KEY: your-api-key-here
{
"isRequired": true,
"items": [
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 1 },
{ "key": "e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28", "text": "Email supplier for signed W-9", "isChecked": false, "position": 2 },
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload W-9 to the vendor file", "isChecked": false, "position": 3 }
]
}
Responses
| Status | Code | When |
|---|
200 OK | — | A Sub-Tasks object. A task with no sub-tasks answers "isRequired": false and an empty items array. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Add Sub-Tasks
Appends one or more sub-tasks to the end of the list, in the order given. This is the only way to put sub-tasks on a task raised through the API. Existing items and their ticks are never changed.
POST /v3/tasks/{taskKey}/sub-tasks
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"items": [
"Email supplier for signed W-9",
"Upload W-9 to the vendor file"
]
}
| Field | Type | Required | Description |
|---|
items | array of string | Yes | The wording of each sub-task to add. At least one. Each is trimmed, must not be blank and must be at most 2,000 characters. One invalid item refuses the whole list before anything is written. Duplicate wording is allowed. |
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"items": [
"Email supplier for signed W-9",
"Upload W-9 to the vendor file"
]
}
{
"added": [
{ "key": "e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28", "text": "Email supplier for signed W-9", "isChecked": false, "position": 2 },
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload W-9 to the vendor file", "isChecked": false, "position": 3 }
],
"isRequired": true,
"items": [
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 1 },
{ "key": "e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28", "text": "Email supplier for signed W-9", "isChecked": false, "position": 2 },
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload W-9 to the vendor file", "isChecked": false, "position": 3 }
]
}
The response is a Sub-Tasks object with one extra field, added: the items this call created, in the order you sent them, so you can take their keys without comparing lists.
Responses
| Status | Code | When |
|---|
201 Created | — | The sub-tasks were added. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; items is missing or empty, or an item is blank or over 2,000 characters (field: items). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Reword or Move a Sub-Task
Changes what one sub-task says, where it sits, or both. Whether it is ticked is deliberately not part of this route, so correcting the wording can never undo somebody's progress — use Tick a Sub-Task and Untick a Sub-Task for that.
PATCH /v3/tasks/{taskKey}/sub-tasks/{itemKey}
This is a partial update of a flat object. Neither field can be cleared, so leaving a field out and sending it as null both mean "leave it alone". Send at least one of the two.
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
itemKey | path | string (GUID) | Yes | The sub-task key, from List Sub-Tasks. |
Request Body
{
"text": "Upload signed W-9 to the vendor file",
"position": 1
}
| Field | Type | Required | Description |
|---|
text | string | No | The new wording. Trimmed; must not be blank; at most 2,000 characters. |
position | integer | No | Where the item should sit, counting from 1. Must be within the list — a position outside it is refused rather than moved to the nearest end. The items in between shift to make room. |
Example
PATCH https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks/4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"text": "Upload signed W-9 to the vendor file",
"position": 1
}
{
"isRequired": true,
"items": [
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload signed W-9 to the vendor file", "isChecked": false, "position": 1 },
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 2 },
{ "key": "e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28", "text": "Email supplier for signed W-9", "isChecked": false, "position": 3 }
]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The whole Sub-Tasks object as it now stands, because a move renumbers the other items. |
400 Bad Request | VALIDATION_ERROR | taskKey or itemKey is not a GUID; the body names neither field; text is blank or over 2,000 characters (field: text); position is outside the list (field: position). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | NOT_FOUND | There is no sub-task with that key on this task. |
Remove a Sub-Task
Removes one sub-task. The remaining items are renumbered from 1. Removing the last one leaves the task with no sub-tasks at all, exactly as if it had never had any.
DELETE /v3/tasks/{taskKey}/sub-tasks/{itemKey}
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
itemKey | path | string (GUID) | Yes | The sub-task key, from List Sub-Tasks. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks/e2d84a17-6c3b-4f90-a1d5-9b0e3c7f5a28
X-API-KEY: your-api-key-here
{
"isRequired": true,
"items": [
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload signed W-9 to the vendor file", "isChecked": false, "position": 1 },
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 2 }
]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The Sub-Tasks object left on the task, renumbered. |
400 Bad Request | VALIDATION_ERROR | taskKey or itemKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | NOT_FOUND | There is no sub-task with that key on this task. |
Tick a Sub-Task
Marks one sub-task done. Ticking an item that is already ticked changes nothing, writes nothing and still answers 200.
POST /v3/tasks/{taskKey}/sub-tasks/{itemKey}/complete
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
itemKey | path | string (GUID) | Yes | The sub-task key, from List Sub-Tasks. |
Request Body
This endpoint takes no request body.
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks/4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53/complete
X-API-KEY: your-api-key-here
{
"isRequired": true,
"items": [
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload signed W-9 to the vendor file", "isChecked": true, "position": 1 },
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 2 }
]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The Sub-Tasks object as it now stands. |
400 Bad Request | VALIDATION_ERROR | taskKey or itemKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | NOT_FOUND | There is no sub-task with that key on this task. |
Notes
Untick a Sub-Task
Marks one sub-task not done again. Unticking an item that is not ticked changes nothing and still answers 200.
DELETE /v3/tasks/{taskKey}/sub-tasks/{itemKey}/complete
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
itemKey | path | string (GUID) | Yes | The sub-task key, from List Sub-Tasks. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/sub-tasks/4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53/complete
X-API-KEY: your-api-key-here
{
"isRequired": true,
"items": [
{ "key": "4a9c3e5d-1b7f-4e26-8d0a-6f2b9c1e7d53", "text": "Upload signed W-9 to the vendor file", "isChecked": false, "position": 1 },
{ "key": "b61f0c9e-2a47-4d15-8e3b-5c9a7f1d2e40", "text": "Confirm supplier tax ID", "isChecked": true, "position": 2 }
]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The Sub-Tasks object as it now stands. |
400 Bad Request | VALIDATION_ERROR | taskKey or itemKey is not a GUID. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
404 Not Found | NOT_FOUND | There is no sub-task with that key on this task. |
Notes
Unticking an item does not change the task's own status. A task that was completed stays completed; use Uncomplete a Standalone Task if it should be reopened.
Returns the tags on the task, by name, ordered by name. The same list is on the Standalone Task object. A standalone task's tags are held against the task itself, so they never appear among the tags of a checklist it is attached to.
GET /v3/tasks/{taskKey}/tags
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Example
GET https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/tags
X-API-KEY: your-api-key-here
{
"tags": ["q3-audit", "urgent"]
}
Responses
| Status | Code | When |
|---|
200 OK | — | The task's tag names. An empty tags array when there are none. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID. |
403 Forbidden | FORBIDDEN | The task is attached to a checklist the member the key acts as may not see. |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Tag a Task
Puts one or more tags on the task, by name. Together with Untag a Task, this is how a task's tags change after it has been raised — Update a Standalone Task does not touch them. See Tags for how tags work across the API.
POST /v3/tasks/{taskKey}/tags
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
Request Body
{
"tags": ["urgent", "vendor-follow-up"]
}
| Field | Type | Required | Description |
|---|
tags | array of string | Yes | The tag names to add. Each is trimmed and at most 100 characters. Names are matched case-insensitively, so Urgent and urgent are one tag. At least one and at most 25, counted after duplicates are collapsed. |
Example
POST https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/tags
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"tags": ["urgent", "vendor-follow-up"]
}
{
"created": ["vendor-follow-up"],
"tags": ["q3-audit", "urgent", "vendor-follow-up"]
}
| Field | Type | Description |
|---|
tags | array of string | Every tag now on the task, ordered by name. |
created | array of string | Tags that did not exist anywhere in the workspace until this call created them. Empty in the ordinary case. |
Responses
| Status | Code | When |
|---|
200 OK | — | The tags are on the task. Naming a tag the task already carries succeeds and writes nothing. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; no tag was named, more than 25 were, or a name is over 100 characters (field: tags). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
A name the workspace has not used before creates a new tag rather than failing, so a misspelling quietly adds a tag. Check created in the response to catch this.
Untag a Task
Takes one tag off the task, by name, matched case-insensitively. The name goes in the query string because a tag name may contain characters, such as /, that a path segment cannot carry.
DELETE /v3/tasks/{taskKey}/tags?name={name}
Parameters
| Name | In | Type | Required | Description |
|---|
taskKey | path | string (GUID) | Yes | The task key. |
name | query | string | Yes | The tag name to remove, URL-encoded. At most 100 characters. |
Example
DELETE https://api.checkflow.io/v3/tasks/7c1e4b2a-9d3f-4a86-b5e2-0f6d8c3a1b97/tags?name=vendor-follow-up
X-API-KEY: your-api-key-here
{
"tagDeleted": true,
"tags": ["q3-audit", "urgent"]
}
| Field | Type | Description |
|---|
tags | array of string | The tags left on the task, ordered by name. |
tagDeleted | boolean | true when that was the tag's last use anywhere in the workspace, so the workspace no longer has the tag. |
Responses
| Status | Code | When |
|---|
200 OK | — | The tag is not on the task. Removing a tag the task was not carrying succeeds, writes nothing and reports tagDeleted false. |
400 Bad Request | VALIDATION_ERROR | taskKey is not a GUID; name is missing, blank or over 100 characters (field: name). |
404 Not Found | TASK_NOT_FOUND | No standalone task in this workspace has that key. |
Notes
Tags are created by being used and removed when nothing uses them any more. There is no separate delete, so removing a tag from its last task or checklist removes it from the workspace.
Related Pages
- Checklist Tasks — the routes for tasks that belong to a checklist, and how they differ from these.
- Checklists — including the list of a checklist's attached tasks.
- My Work — find standalone tasks alongside checklist tasks, and snooze several at once.
- Standalone Task Tools — the same operations as MCP tools.
- Tasks Overview — standalone, attached and checklist tasks as they appear in the app.