Task Fields and Files
A task's fields are its input controls — the Short Text, Dropdown, Members and other controls a person fills in when they work through a checklist. The routes on this page read what each field holds and write new answers into them. They are how you fill a task in through the API; completing the task afterwards is on Checklist Tasks.
Most fields hold a single value and are answered with one PUT. Two do not. A File Upload control holds files, each with an id of its own, so its files are a sub-resource you add to and remove from. A Table control holds cells, so its rows are a sub-resource you read and write a cell at a time. Both still appear in the field list, so a single read shows everything on the task.
Every route here starts by finding the checklist in the key's workspace and the task inside it. A checklist in another workspace is reported as CHECKLIST_NOT_FOUND rather than forbidden. Changes are recorded against the key's actor, as described in Authentication.
Every write on this page accepts an Idempotency-Key header (see Idempotency) and every route is charged to the standard rate limit budget (see Rate Limits). Retrying a row insert or a row delete without one is not safe: each call adds or removes another row.
Endpoints
All paths start /v3/checklists/{checklistKey}/tasks/{taskKey}, shortened to … below.
| Method | Path | Description | MCP tool |
|---|---|---|---|
GET | …/fields | Get task fields | get_task_fields |
PUT | …/fields | Answer several task fields | set_task_fields |
GET | …/fields/{fieldKey} | Get a task field | — |
PUT | …/fields/{fieldKey} | Answer a task field | set_task_fields |
GET | …/fields/{fieldKey}/files | List the files on a field | get_task_files |
POST | …/fields/{fieldKey}/files | Add a file to a field | — |
DELETE | …/fields/{fieldKey}/files/{fileId} | Remove a file from a field | remove_task_file |
GET | …/fields/{fieldKey}/rows | Get the rows of a table | get_task_table_rows |
POST | …/fields/{fieldKey}/rows | Add a table row | add_task_table_row |
DELETE | …/fields/{fieldKey}/rows/{rowIndex} | Remove a table row | remove_task_table_row |
PUT | …/fields/{fieldKey}/rows/{rowIndex}/cells/{columnIndex} | Set a table cell | set_task_table_cell |
The Field Object
A field as the field routes report it. value is untyped: its shape depends on type, and the Value Format Reference gives it for every type. The write routes take the same shapes back, so you can read a field, change its value and send it straight back.
| Field | Type | Description |
|---|---|---|
key | string (GUID) | The field's key. Every route that acts on one field takes it as fieldKey. |
name | string | The control's label. When the template author left the label empty, a position-based name such as Unlabelled Email Input Content at Position 3. |
type | string | The control type: ShortText, LongText, EmailInput, Website, Date, DropDown, MultiChoice, SubTasks, Members, FileUpload, File or Table. See Value Format Reference. |
isRequired | boolean | Whether the task can be completed without an answer here. For a FileUpload, true when the template sets a minimum number of files. Always false for File and Table (a table's cells carry their own flag — see The Table Object). |
mode | string | Date only: date, time or date-and-time. Absent for every other type. See Date & Time. |
regex | string | ShortText only, and only when the template sets a pattern: the pattern an answer must match, exactly as the template stores it — possibly wrapped in slashes, which the API strips before applying it. Absent otherwise. |
regexMessage | string | The message the template author wrote for an answer that does not match regex. Absent when there is no pattern or no message. |
selectionMode | string | Members only: single or multiple. Absent for every other type. |
options | array of string | The answers the field accepts, where they are a fixed list not already visible in value. A DropDown's option texts, or the display names of everybody a Members field offers. Absent for every other type and for a Dropdown that reads from a Data Set. |
dataSet | DataSet link | Present when the field's choices or rows come from a Data Set — a DropDown, MultiChoice, SubTasks or Table. Absent otherwise. |
value | varies | What the field currently holds. Absent when a Date & Time or Dropdown has no answer. |
{
"key": "c2e7a915-4b8d-4f3a-9e61-5d0b7a2c8f13",
"name": "Invoice Number",
"type": "ShortText",
"isRequired": true,
"regex": "/^INV-\\d{4}$/",
"regexMessage": "Use the form INV-1234",
"value": "INV-2041"
}
The DataSet Link Object
Where a field's choices or rows come from. A task read reports the keys only: name, viewName and displayFieldName are absent unless the Data Set is one of the built-in system Data Sets. GET /v3/data-sets/{key} has the names.
| Field | Type | Description |
|---|---|---|
key | string (GUID) | The Data Set's key. |
name | string | The Data Set's name. Absent on a task read unless the Data Set is built in. |
viewKey | string (GUID) | The view whose records are the choices. Pass it as view to the Data Set records route to list them. |
viewName | string | The view's name. Absent on a task read unless the Data Set is built in. |
displayFieldKey | string (GUID) | The Data Set field whose value each choice shows. This is what a linked answer's text is. Absent on a Table. |
displayFieldName | string | The display field's name. Absent on a task read unless the Data Set is built in. |
prePopulateRows | boolean | Tables only: whether a checklist starts with one row per record of the view. Always present, and false on the other types. |
columns | array | Tables only: which Data Set field fills which column, as fieldKey, fieldName (absent on a task read) and column (counting from 1). Absent on the other types. |
{
"key": "e4a7c2d9-1b6f-4e38-9a05-c8d3f6b1a724",
"viewKey": "0f3b9e6a-7d2c-4a18-b5e9-4c61d8a2f307",
"displayFieldKey": "9d2e5a18-6c4b-4f07-8e3a-b71f0c6d4e95",
"prePopulateRows": false
}
Value Format Reference
What each input control holds, in the shape the reads return and the writes accept. Several rules apply to every type:
null, and a body with novalueat all, clears a field. So does an empty list for the list-valued types, and an empty string for the text types and a manual Dropdown.- A list-valued write — Multi-Choice, Sub-Tasks, Members — is a replacement. Anything you leave out is deselected, unticked or removed.
- Option and item texts are matched ignoring case and surrounding spaces.
isRequiredis not enforced when you write. Clearing a required field is accepted; the requirement is checked when the task is completed.- A value of the wrong shape is refused with
400 VALIDATION_ERRORnamingvalue(orfields[n].valuein a batch), and the message says what the field takes.
| Control | type | Read as | Write as |
|---|---|---|---|
| Short Text | ShortText | string | string |
| Long Text | LongText | string | string |
EmailInput | string | string | |
| Website | Website | string | string |
| Date & Time | Date | ISO 8601 UTC string | ISO 8601 string |
| Dropdown | DropDown | the selected option's text | an option's text |
| Multi-Choice | MultiChoice | every item, with isSelected | list of texts, or the read's own shape |
| Sub-Tasks | SubTasks | every item, with isChecked | list of texts, or the read's own shape |
| Members | Members | list of {id, type, name} | list of names, emails or {type, id} |
| Data Set-linked Dropdown or Multi-Choice | DropDown, MultiChoice | {recordKey, text}, or a list of them | a record's key or display text |
| File Upload | FileUpload | list of files | not writable here — use the files routes |
| File (template-supplied files) | File | list of files | not writable |
| Table | Table | flat list of {row, column, value} | not writable here — use the rows routes |
Short Text, Long Text, E-Mail and Website
Read as a string. An unanswered field reads as an empty string.
Written as a string. A JSON number or boolean is also accepted and stored as its text (42 becomes "42", true becomes "true"). An array or object is refused.
- Short Text with a
regexrefuses an answer that does not match the pattern. The error message includes the template'sregexMessage, or Invalid value entered when there is none. An empty value is not checked against the pattern, so you can always clear the field. - E-Mail and Website answers are stored as sent. The API does not check that the text is an email address or a web address.
{ "value": "INV-2041" }
Date & Time
Read as an ISO 8601 UTC timestamp, such as "2026-09-14T00:00:00Z". An unanswered field has no value.
Written as a string the API can read as a date. A value with no offset is read as UTC; a value with an offset is converted, so "2026-12-01T17:00:00+02:00" is stored and read back as "2026-12-01T15:00:00Z". An empty string clears the field, the same as null. Text that is not a date is refused rather than stored as empty, and a number is refused.
Read mode before you read or write the value. All three modes store a whole timestamp in the same column:
mode | What the field means | How to write it |
|---|---|---|
date | A calendar date, kept at midnight UTC. | Send the date at T00:00:00Z. Converting the value into a zone west of UTC shows the previous day. |
time | A time of day. The date part is not meaningful. | Send the time on any date. |
date-and-time | An instant. | Send the instant, with an offset or in UTC. |
The API does not check the value against mode.
{ "value": "2026-09-14T00:00:00Z" }
Dropdown
Read as the selected option's text. An unanswered Dropdown has no value. options lists every option it offers.
Written as the text of one of its options, matched ignoring case and surrounding spaces, so " hIgH " selects High. An option the Dropdown does not offer is refused, and the error lists the options:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "'Priority' has no option named 'Urgnet'. Its options are 'Low', 'Medium', 'High'.",
"requestId": "req_4f1c2b7e9a0d4c3b8e6f1a2b3c4d5e6f",
"field": "value"
}
}
null or an empty string clears the selection. A list or an object is refused.
A Dropdown that reads its options from a Data Set is answered differently — see Data Set-Linked Dropdown and Multi-Choice.
Multi-Choice
Read as every item with an isSelected flag, which is why a Multi-Choice has no options:
[
{ "text": "Operations", "isSelected": true },
{ "text": "Marketing", "isSelected": false },
{ "text": "Finance", "isSelected": false }
]
Written in either of two shapes:
- A list of the texts to select:
["Operations", "Finance"]. - The read's own shape. An item with
"isSelected": falseis deselected, the same as leaving it out.
Either way the write is a replacement: exactly the items you name are selected afterwards. Every name that matches no item is refused in one error, which lists the unmatched names and the item texts, and nothing is written. null or [] clears every item.
Sub-Tasks
The same as Multi-Choice with the flag spelt isChecked:
[
{ "text": "PO number matches", "isChecked": true },
{ "text": "Totals agree", "isChecked": false }
]
Write ["PO number matches", "Totals agree"] to tick both, or send the read's shape back. It is a replacement, so an item you leave out is unticked. You cannot add or remove items on a checklist task's Sub-Tasks control through this route — only tick and untick the items the template gave it. A Sub-Tasks control built from a Data Set carries dataSet and is answered the same way, by item text.
Members
Read as a list of the selected people and groups:
[
{ "id": 1042, "type": "TeamMember", "name": "Sarah Chen" },
{ "id": 17, "type": "Group", "name": "Finance Team" }
]
type is TeamMember or Group. name is absent for somebody who has since left the workspace.
options lists the display names of everybody the field offers. That is the people and groups the template gave the control, less any it excludes — not the whole workspace. selectionMode says whether it takes one or several.
Written as a list whose entries can be mixed:
- A display name — a member's full name or a group's name:
"Sarah Chen","Finance Team". - A member's email address:
"sarah.chen@acme.example". - An object with
typeandid, as the read returns it:{"type": "TeamMember", "id": 1042}.typeis required alongsideid, because a member and a group can share an id. Anamesent alongside anidis ignored.
It is a replacement. Naming the same person twice, for example by name and by id, is accepted and selects them once. null or [] clears the field. Each of these is refused with 400 and nothing is written:
| Refused | Why |
|---|---|
| A name the field does not offer | The message says the field does not offer anybody by that name. |
| A person the template excludes from this control | The message says they are excluded, rather than unknown. |
| A name that matches more than one person or group | The message lists each match as a type and id, so you can name one by id. |
An id without a type, or a type other than TeamMember or Group | An id alone does not say which table it is in. |
More than one person on a field whose selectionMode is single | The API refuses rather than keeping the first. |
Data Set-Linked Dropdown and Multi-Choice
A Dropdown or Multi-Choice that reads its choices from a Data Set carries dataSet, and its answer is a record from that view rather than an option's text. It has no options: its choices are the view's records, which you list with the Data Set records route, passing dataSet.viewKey as the view (see Data Sets).
Read as the selected record — or, for a Multi-Choice, a list of the selected records only:
{ "recordKey": "71c4e8b2-3a9d-4f65-8b10-e2d7a6c93f41", "text": "Northwind Traders" }
text is the record's value in the display field, as the option showed it when it was chosen. An unanswered linked Dropdown has no value; an unanswered linked Multi-Choice reads as [].
Written as a record, in any of these forms:
{"recordKey": "…"}— exact. If you also sendtext, it is not checked.- The words the option shows, as a string or as
{"text": "…"}, matched against the display field ignoring case and surrounding spaces.
A Dropdown takes one record and refuses a list; a Multi-Choice takes a list and refuses a single value, and its write is a replacement. null clears a linked Dropdown and null or [] clears a linked Multi-Choice. An empty string is refused on a linked Dropdown. These are also refused with 400:
- A
recordKeythat is not a GUID, or that is not in the view. - Words that no record shows. Use the records route to see what the view offers.
- Words that more than one record shows. The message lists the matching record keys; send one as
recordKey. - A field whose Data Set view no longer exists, or a field that holds a Data Set answer but no longer reads from a view.
What is stored is the record and a snapshot of its values, so the controls on the checklist that are bound to that record's fields fill in, as they do on the checklist page. The write's response shows them.
File Upload and File
Both read as a list of the control's files, each with the id that removes it:
[
{
"id": 88213,
"name": "INV-2041.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/5e2a9c47d1b84f36a0e7c3d9b2f18a64.pdf"
}
]
FileUpload is the File Upload control. File is a control whose files the template supplied, such as the File content control; it takes no uploads. Neither can be answered with PUT …/fields/{fieldKey} — that is refused with 400 and a message pointing at the files routes. Use the files routes to see who uploaded each file and to add and remove them.
A file's url is not behind your API key. Anybody holding the address can download the file, so treat it as a secret rather than a link to publish.
Table
Read as a flat list of every cell's position and text, which is enough to read a table but not to write one:
[
{ "row": 1, "column": 1, "value": "Description" },
{ "row": 1, "column": 2, "value": "Amount" },
{ "row": 2, "column": 1, "value": "Consulting" },
{ "row": 2, "column": 2, "value": "1200.00" }
]
A Table cannot be answered as a whole — PUT …/fields/{fieldKey} is refused with 400. Use the rows routes, which also say which cells are read-only and whether rows can be added or removed.
Controls That Are Not Fields
Content controls — Text, Image, Video, Embed, Separator and Mail-To — hold no answer and are left out of the field list. So is the Linked Checklist control, which creates a child checklist rather than holding a value.
Get a task field still returns one of these if you ask for it by key, with its type (Text, Image, Video, Embed, Separator, SendEmail for Mail-To, or LinkedChecklist) and no value. Writing one is refused with 400: the message says it displays content rather than holding an answer.
Hidden Fields and Task State
A field that a conditional logic rule is currently hiding:
- is left out of Get task fields and out of every write's response;
- is still returned by Get a task field, List the files on a field and Get the rows of a table when you ask for it by key — but nothing in those responses says it is hidden;
- refuses every write with
409 CONFLICT. Changing the answers that hide it may reveal it.
Only the field's own hidden state is checked. The field routes do not refuse a write because the task is complete, marked not applicable or halted by task order.
What a Field Write Does
Every successful write to a field value (either PUT on …/fields):
- Stores the answer and records an entry in the task's activity feed. Writing a value the field already holds is still a write, with its own activity entry.
- Propagates it straight away. A Data Set-linked answer fills in the controls bound to the record's fields, and a dynamic value binding copies the answer into the controls that point at this one. That is why the response is the task's whole field set, re-read after the write, rather than the field you wrote.
- Queues the rest of the checklist's reaction, which happens shortly afterwards in the background: conditional logic is re-evaluated (showing or hiding tasks and fields), dynamic task assignments that read a Members field are re-evaluated, linked controls are pushed to child checklists, and people assigned to a task that has just become visible are notified. A batch queues this once per call, however many fields it writes.
Because conditional logic is re-evaluated after the response is sent, a field or task that your answer reveals or hides may not be reflected in the response. Read the fields again if you need the settled state.
Get Task Fields
Returns every field on a task that is not currently hidden, in the order they appear on the task. This is the same set of fields the task read carries, without the rest of the task.
GET /v3/checklists/{checklistKey}/tasks/{taskKey}/fields
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
Example
GET https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
{
"fields": [
{
"key": "c2e7a915-4b8d-4f3a-9e61-5d0b7a2c8f13",
"name": "Invoice Number",
"type": "ShortText",
"isRequired": true,
"regex": "/^INV-\\d{4}$/",
"regexMessage": "Use the form INV-1234",
"value": "INV-2041"
},
{
"key": "5b9f0c3d-2e8a-4d71-b6c4-a13e7f9d2058",
"name": "Supplier",
"type": "DropDown",
"isRequired": true,
"dataSet": {
"key": "e4a7c2d9-1b6f-4e38-9a05-c8d3f6b1a724",
"viewKey": "0f3b9e6a-7d2c-4a18-b5e9-4c61d8a2f307",
"displayFieldKey": "9d2e5a18-6c4b-4f07-8e3a-b71f0c6d4e95",
"prePopulateRows": false
},
"value": {
"recordKey": "71c4e8b2-3a9d-4f65-8b10-e2d7a6c93f41",
"text": "Northwind Traders"
}
},
{
"key": "1e6c3a8f-9b2d-4e57-a4f0-6d8b2c7e1a39",
"name": "Invoice Date",
"type": "Date",
"isRequired": true,
"mode": "date",
"value": "2026-09-14T00:00:00Z"
},
{
"key": "3a8e6f21-9c4d-4b17-a2e5-d06b8f3c7a94",
"name": "Priority",
"type": "DropDown",
"isRequired": false,
"options": ["Low", "Medium", "High"]
},
{
"key": "a47e2c91-5f3d-4b08-9c6e-2b8d1f4a7e53",
"name": "Cost Centres",
"type": "MultiChoice",
"isRequired": true,
"value": [
{ "text": "Operations", "isSelected": true },
{ "text": "Marketing", "isSelected": false },
{ "text": "Finance", "isSelected": false }
]
},
{
"key": "2c8b5e7a-1d4f-4396-a8e2-9f0c3b6d1e74",
"name": "Checks",
"type": "SubTasks",
"isRequired": false,
"value": [
{ "text": "PO number matches", "isChecked": true },
{ "text": "Totals agree", "isChecked": false }
]
},
{
"key": "f1a6d3b8-7c2e-4a59-b4d1-8e0f2c5a9d63",
"name": "Supplier E-mail",
"type": "EmailInput",
"isRequired": false,
"value": ""
},
{
"key": "93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716",
"name": "Invoice PDF",
"type": "FileUpload",
"isRequired": true,
"value": [
{
"id": 88213,
"name": "INV-2041.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/5e2a9c47d1b84f36a0e7c3d9b2f18a64.pdf"
}
]
},
{
"key": "4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28",
"name": "Line Items",
"type": "Table",
"isRequired": false,
"value": [
{ "row": 1, "column": 1, "value": "Description" },
{ "row": 1, "column": 2, "value": "Amount" },
{ "row": 2, "column": 1, "value": "Consulting" },
{ "row": 2, "column": 2, "value": "1200.00" }
]
}
]
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The task's fields. |
400 | VALIDATION_ERROR | checklistKey or taskKey is not a GUID. field names which. |
403 | FORBIDDEN | The member the key acts as may not see this checklist. See Who Can Change a Task. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
Get a Task Field
Returns one field by its key. Unlike the list, it returns a field a condition is currently hiding, and a content control if you name one.
GET /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The field's key, from the field list. |
Example
GET https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/1e6c3a8f-9b2d-4e57-a4f0-6d8b2c7e1a39
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
{
"key": "1e6c3a8f-9b2d-4e57-a4f0-6d8b2c7e1a39",
"name": "Invoice Date",
"type": "Date",
"isRequired": true,
"mode": "date",
"value": "2026-09-14T00:00:00Z"
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The field. |
400 | VALIDATION_ERROR | A key in the path is not a GUID. field names which. |
403 | FORBIDDEN | The member the key acts as may not see this checklist. See Who Can Change a Task. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
Answer a Task Field
Puts a value in one field. To answer several fields on the same task, use Answer several task fields instead: one call costs one read, one round of propagation and one queued re-evaluation, where several calls cost one each.
PUT /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The field's key, from the field list. |
Request Body
{
"value": ["Sarah Chen"]
}
| Field | Type | Required | Description |
|---|---|---|---|
value | varies | No | The answer, in the shape the Value Format Reference gives for the field's type. null or leaving it out clears the field, so {} is a valid body that clears it. |
Example
Selecting the approver on a single-selection Members field:
PUT https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/d5b2e8f1-4c7a-4e36-9a1d-0b6f3c8e2a57/fields/6d3a9f14-8e2b-4c75-b0a6-3f1e7d5c9b82
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"value": ["Sarah Chen"]
}
HTTP/1.1 200 OK
{
"fields": [
{
"key": "6d3a9f14-8e2b-4c75-b0a6-3f1e7d5c9b82",
"name": "Approver",
"type": "Members",
"isRequired": true,
"selectionMode": "single",
"options": ["James Okafor", "Priya Patel", "Sarah Chen", "Finance Team"],
"value": [
{ "id": 1042, "type": "TeamMember", "name": "Sarah Chen" }
]
},
{
"key": "0c7e3b9a-5d2f-4a81-b6e4-9f1d8a2c5e37",
"name": "Approval Notes",
"type": "LongText",
"isRequired": false,
"value": ""
},
{
"key": "7b4f1d8e-2a6c-4953-8e0b-c3a9f5d1e764",
"name": "Approved On",
"type": "Date",
"isRequired": true,
"mode": "date-and-time"
}
]
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The task's whole field set, re-read after the write and the bindings it set off. Same shape as Get task fields. |
400 | VALIDATION_ERROR | A key in the path is not a GUID; the body is not valid JSON; or the value is refused (field is value) — the wrong shape for the type, an option or person the field does not offer, a Short Text pattern mismatch, text that is not a date, or a field that cannot be answered this way (File Upload, File, Table or a content control). See Value Format Reference. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
409 | CONFLICT | A condition is hiding the field. |
Notes
See What a Field Write Does for the activity entry, propagation and background re-evaluation every write triggers.
Answer Several Task Fields
Fills in several fields on one task in a single call. Each entry takes the same value shapes as Answer a task field.
The batch is all or nothing. Every entry is checked — including looking up Data Set records — before any is written, so a batch that names one missing field, one hidden field or one bad value writes none of them.
PUT /v3/checklists/{checklistKey}/tasks/{taskKey}/fields
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
Request Body
{
"fields": [
{ "key": "6d3a9f14-8e2b-4c75-b0a6-3f1e7d5c9b82", "value": ["sarah.chen@acme.example"] },
{ "key": "0c7e3b9a-5d2f-4a81-b6e4-9f1d8a2c5e37", "value": "Approved within the Q3 budget." },
{ "key": "7b4f1d8e-2a6c-4953-8e0b-c3a9f5d1e764", "value": "2026-09-15T16:30:00Z" }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
fields | array | Yes | The answers. At least 1 and at most 50 entries. |
fields[].key | string (GUID) | Yes | The field's key. Each field may be named once; two entries for the same field are refused, even if the GUID is spelt differently. |
fields[].value | varies | No | The answer, as for the single write. null or leaving it out clears the field. |
Example
PUT https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/d5b2e8f1-4c7a-4e36-9a1d-0b6f3c8e2a57/fields
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"fields": [
{ "key": "6d3a9f14-8e2b-4c75-b0a6-3f1e7d5c9b82", "value": ["sarah.chen@acme.example"] },
{ "key": "0c7e3b9a-5d2f-4a81-b6e4-9f1d8a2c5e37", "value": "Approved within the Q3 budget." },
{ "key": "7b4f1d8e-2a6c-4953-8e0b-c3a9f5d1e764", "value": "2026-09-15T16:30:00Z" }
]
}
HTTP/1.1 200 OK
{
"fields": [
{
"key": "6d3a9f14-8e2b-4c75-b0a6-3f1e7d5c9b82",
"name": "Approver",
"type": "Members",
"isRequired": true,
"selectionMode": "single",
"options": ["James Okafor", "Priya Patel", "Sarah Chen", "Finance Team"],
"value": [
{ "id": 1042, "type": "TeamMember", "name": "Sarah Chen" }
]
},
{
"key": "0c7e3b9a-5d2f-4a81-b6e4-9f1d8a2c5e37",
"name": "Approval Notes",
"type": "LongText",
"isRequired": false,
"value": "Approved within the Q3 budget."
},
{
"key": "7b4f1d8e-2a6c-4953-8e0b-c3a9f5d1e764",
"name": "Approved On",
"type": "Date",
"isRequired": true,
"mode": "date-and-time",
"value": "2026-09-15T16:30:00Z"
}
]
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The task's whole field set, re-read after the writes. |
400 | VALIDATION_ERROR | A path key is not a GUID; the body is not valid JSON; fields is missing, empty or has more than 50 entries (field is fields); an entry's key is not a GUID or repeats an earlier entry (fields[n].key); or an entry's value is refused (fields[n].value), for the reasons listed under Answer a task field. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with one of the keys. Nothing is written. |
409 | CONFLICT | A condition is hiding one of the fields. Nothing is written. |
The Files Object
The files on one File Upload (or template-supplied File) control, with the control's own limits. The write routes return the same object with one extra property.
| Field | Type | Description |
|---|---|---|
fieldKey | string (GUID) | The control's key. |
fieldName | string | The control's label, or a position-based name when it has none. |
minFiles | integer | How many files the control needs before the task can be completed, or 0 for no minimum. Reported here and checked on completion, not on upload. |
maxFiles | integer | The most files the control holds, or 0 for no maximum. Enforced on upload. |
isReadOnly | boolean | true for a control whose files the template supplied (type File on the field read). Both writes refuse it. |
files | array of file | Every file on the control. |
file | file | Add a file only: the file that call added, so you do not have to find its id in files. |
blobDeleted | boolean | Remove a file only: whether the stored bytes were deleted along with the file. |
File
| Field | Type | Description |
|---|---|---|
id | integer | The file's id. The remove route takes it. It is only meaningful on this control. |
name | string | The name the file was uploaded under. Names are not unique: the same name can be on a control twice. |
contentType | string | The media type recorded at upload, as the uploader gave it. |
url | string | Where the file's bytes are. Not behind your API key — anybody with the address can download the file. |
description | string | The note kept with the file. Absent when there is none. |
uploadedDateTime | string (date-time) | When the file was uploaded. |
uploadedBy | object | Who uploaded it: name and email. Absent when they have since left the workspace. |
{
"fieldKey": "93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716",
"fieldName": "Invoice PDF",
"minFiles": 1,
"maxFiles": 3,
"isReadOnly": false,
"files": [
{
"id": 88213,
"name": "INV-2041.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/5e2a9c47d1b84f36a0e7c3d9b2f18a64.pdf",
"description": "Supplier copy",
"uploadedDateTime": "2026-09-14T10:22:05Z",
"uploadedBy": {
"name": "James Okafor",
"email": "james.okafor@acme.example"
}
}
]
}
List the Files on a Field
Returns the files on a File Upload control with who uploaded each one, when and the note kept with it, plus the control's minimum and maximum. The field read carries a shorter list of the same files. This route also answers for a control a condition is hiding and for a read-only File control.
GET /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/files
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a FileUpload or File field. |
Example
GET https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716/files
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
The response is the Files object example above.
Responses
| Status | Code | When |
|---|---|---|
200 | — | The Files object. |
400 | VALIDATION_ERROR | A path key is not a GUID, or the field does not hold files (field is fieldKey). |
403 | FORBIDDEN | The member the key acts as may not see this checklist. See Who Can Change a Task. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
Add a File to a Field
Uploads one file to a File Upload control. The file's bytes go in a JSON body, base64 encoded — this route does not take a multipart form.
POST /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/files
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a FileUpload field. |
Request Body
{
"name": "INV-2041-credit-note.pdf",
"content": "JVBERi0xLjcKJeLjz9MK",
"contentType": "application/pdf",
"description": "Credit note from Northwind Traders"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | The name the file is listed under. Surrounding spaces are trimmed, and a name that is blank after trimming is refused. Not checked for uniqueness. |
content | string | Yes | The file's bytes, base64 encoded. At most 32 MB once decoded. An empty file is refused. |
contentType | string | No | The media type to record, such as application/pdf. Defaults to application/octet-stream. Not validated against the bytes. |
description | string | No | A note to keep with the file. |
No file type is blocked.
Example
POST https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716/files
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"name": "INV-2041-credit-note.pdf",
"content": "JVBERi0xLjcKJeLjz9MK",
"contentType": "application/pdf",
"description": "Credit note from Northwind Traders"
}
HTTP/1.1 201 Created
{
"fieldKey": "93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716",
"fieldName": "Invoice PDF",
"minFiles": 1,
"maxFiles": 3,
"isReadOnly": false,
"files": [
{
"id": 88213,
"name": "INV-2041.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/5e2a9c47d1b84f36a0e7c3d9b2f18a64.pdf",
"description": "Supplier copy",
"uploadedDateTime": "2026-09-14T10:22:05Z",
"uploadedBy": {
"name": "James Okafor",
"email": "james.okafor@acme.example"
}
},
{
"id": 88240,
"name": "INV-2041-credit-note.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/b81f3e6a2c9d4705a4e1d8c67f2b093e.pdf",
"description": "Credit note from Northwind Traders",
"uploadedDateTime": "2026-09-15T08:41:17Z",
"uploadedBy": {
"name": "Priya Patel",
"email": "priya.patel@acme.example"
}
}
],
"file": {
"id": 88240,
"name": "INV-2041-credit-note.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/b81f3e6a2c9d4705a4e1d8c67f2b093e.pdf",
"description": "Credit note from Northwind Traders",
"uploadedDateTime": "2026-09-15T08:41:17Z",
"uploadedBy": {
"name": "Priya Patel",
"email": "priya.patel@acme.example"
}
}
}
Responses
| Status | Code | When |
|---|---|---|
201 | — | The Files object, with the new file in file. |
400 | VALIDATION_ERROR | A path key is not a GUID; the body is not valid JSON; name is missing or blank (field is name); content is missing, not valid base64, empty or larger than 32 MB decoded (content); or the field does not hold files, or is a read-only File control (fieldKey). |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
409 | CONFLICT | A condition is hiding the field, or it already holds maxFiles files. Remove one before adding another. |
Notes
- Uploading the same name twice adds a second file; it does not replace the first.
- The upload records an entry in the task's activity feed and triggers any webhook subscribed to
file_uploaded. - Base64 makes the request about a third larger than the file.
Remove a File from a Field
Takes one file off a File Upload control, by the id a read gave it.
DELETE /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/files/{fileId}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a FileUpload field. |
fileId | path | integer | Yes | The file's id, from the files list or the field's value. Must be on this control. |
Example
DELETE https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716/files/88240
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
{
"fieldKey": "93e1b7c4-2a6f-4d85-9b3e-c0f5a8d2e716",
"fieldName": "Invoice PDF",
"minFiles": 1,
"maxFiles": 3,
"isReadOnly": false,
"files": [
{
"id": 88213,
"name": "INV-2041.pdf",
"contentType": "application/pdf",
"url": "https://acmefiles.blob.core.windows.net/uploads/5e2a9c47d1b84f36a0e7c3d9b2f18a64.pdf",
"description": "Supplier copy",
"uploadedDateTime": "2026-09-14T10:22:05Z",
"uploadedBy": {
"name": "James Okafor",
"email": "james.okafor@acme.example"
}
}
],
"blobDeleted": true
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The Files object with the remaining files and blobDeleted. |
400 | VALIDATION_ERROR | A path key is not a GUID; fileId is not a positive whole number (field is fileId); or the field does not hold files, or is a read-only File control (fieldKey). |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
404 | FILE_NOT_FOUND | The control has no file with that id — it was already removed, or belongs to another control. |
409 | CONFLICT | A condition is hiding the field. |
Notes
- A file on a checklist can share its stored bytes with the template it came from and with other checklists built from that template. Removing such a file takes it off this task and leaves the bytes in place, so
blobDeletedisfalse. That is the normal result, not a failure. When no other file uses the bytes, they are deleted andblobDeletedistrue. - The removal records an entry in the task's activity feed.
When blobDeleted is true the file's bytes are permanently deleted and cannot be recovered.
The Table Object
One Table control as rows and cells, with everything that decides whether a write will be accepted. Every table write returns the whole table re-read, because adding or removing a row renumbers the rows after it.
Rows and columns are numbered from 1. Row 1 is normally the header row the template wrote. Indexes are stored rather than computed, so they need not be contiguous; read them again after a write rather than keeping them.
| Field | Type | Description |
|---|---|---|
fieldKey | string (GUID) | The control's key. |
fieldName | string | The control's label, or a position-based name when it has none. |
columns | integer | How many columns the template set. Cells are numbered 1 to this. On an old table whose column count changed after it was filled in, rows[].cells is what actually exists. |
allowAddRemoveRows | boolean | Whether the template allows rows to be added and removed. When false, both row writes are refused with 403. |
isDataSetLinked | boolean | true when rows were filled from Data Set records. Those rows' cells are read-only and carry recordKey. |
rows | array of row | Every row, in index order. |
addedRow | row | Add a table row only: the row just added, at the index it ended up at. |
removedRow | integer | Remove a table row only: the index that was removed. It no longer names anything. |
cell | cell | Set a table cell only: the cell as it now stands. |
changed | boolean | Set a table cell only: false when the cell already held that value and nothing was written. |
Row
| Field | Type | Description |
|---|---|---|
index | integer | The row's index. The row routes take it as rowIndex, and the insert takes it as afterRow or beforeRow. |
isDeletable | boolean | Whether Remove a table row would succeed on this row now: the template allows rows to be removed, the table has more than one row, and at least one of the row's cells is not read-only. |
cells | array of cell | The row's cells, in column order. |
Cell
| Field | Type | Description |
|---|---|---|
row | integer | The row the cell is in. |
column | integer | The column the cell is in, counting from 1. |
value | string | What the cell holds. An empty cell reads as an empty string. |
isReadOnly | boolean | true when the cell refuses writes. A cell is read-only when the template author marked it so, when it is mapped to a Data Set field, or — most often — when the template saved it with text in it. |
isRequired | boolean | Whether the template marked the cell as required. Reported only: nothing enforces it, and a task whose table has empty required cells can still be completed. |
format | string | How the template meant the cell to be read: PlainText, Number, Percent, Date, Time or DateTime. A hint only — every value is stored as text and nothing parses it. |
recordKey | string (GUID) | The Data Set record the cell's row came from. Absent for rows that did not come from a record. |
{
"fieldKey": "4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28",
"fieldName": "Line Items",
"columns": 2,
"allowAddRemoveRows": true,
"isDataSetLinked": false,
"rows": [
{
"index": 1,
"isDeletable": false,
"cells": [
{ "row": 1, "column": 1, "value": "Description", "isReadOnly": true, "isRequired": false, "format": "PlainText" },
{ "row": 1, "column": 2, "value": "Amount", "isReadOnly": true, "isRequired": false, "format": "PlainText" }
]
},
{
"index": 2,
"isDeletable": true,
"cells": [
{ "row": 2, "column": 1, "value": "Consulting", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 2, "column": 2, "value": "1200.00", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
}
]
}
Get the Rows of a Table
Returns a Table control as a Table object. Read this before writing: isReadOnly on each cell and isDeletable on each row say in advance which writes will be refused. It also answers for a table a condition is hiding.
GET /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/rows
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a Table field. |
Example
GET https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28/rows
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
The response is the Table object example above.
Responses
| Status | Code | When |
|---|---|---|
200 | — | The Table object. |
400 | VALIDATION_ERROR | A path key is not a GUID, or the field is not a table (field is fieldKey). |
403 | FORBIDDEN | The member the key acts as may not see this checklist. See Who Can Change a Task. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
Add a Table Row
Inserts one row next to an existing row. The new row's cells copy that row's formats, required flags and read-only state, and the text of its read-only cells, which are the template's labels. Editable cells start empty. In a Data Set-linked table, the new row is your own entry: its cells are editable and not required.
POST /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/rows
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a Table field. |
Request Body
{
"afterRow": 2
}
Give exactly one of the two.
| Field | Type | Required | Description |
|---|---|---|---|
afterRow | integer | One of the two | Insert immediately below this row. The new row takes the next index and every row below moves down one. |
beforeRow | integer | One of the two | Insert immediately above this row. The new row takes this index, and this row and every row below it move down one. |
Example
POST https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28/rows
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"afterRow": 2
}
HTTP/1.1 201 Created
{
"fieldKey": "4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28",
"fieldName": "Line Items",
"columns": 2,
"allowAddRemoveRows": true,
"isDataSetLinked": false,
"rows": [
{
"index": 1,
"isDeletable": false,
"cells": [
{ "row": 1, "column": 1, "value": "Description", "isReadOnly": true, "isRequired": false, "format": "PlainText" },
{ "row": 1, "column": 2, "value": "Amount", "isReadOnly": true, "isRequired": false, "format": "PlainText" }
]
},
{
"index": 2,
"isDeletable": true,
"cells": [
{ "row": 2, "column": 1, "value": "Consulting", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 2, "column": 2, "value": "1200.00", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
},
{
"index": 3,
"isDeletable": true,
"cells": [
{ "row": 3, "column": 1, "value": "", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 3, "column": 2, "value": "", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
}
],
"addedRow": {
"index": 3,
"isDeletable": true,
"cells": [
{ "row": 3, "column": 1, "value": "", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 3, "column": 2, "value": "", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
}
}
Responses
| Status | Code | When |
|---|---|---|
201 | — | The Table object, with the new row in addedRow. Read the new row's index from addedRow.index: with afterRow it is one more than the row you named, and with beforeRow it is the row you named. |
400 | VALIDATION_ERROR | A path key is not a GUID; the body is not valid JSON; neither or both of afterRow and beforeRow are given (field is afterRow); the row named is not in the table (afterRow or beforeRow, whichever you sent); or the field is not a table (fieldKey). |
403 | FORBIDDEN | The template does not allow this table's rows to be added or removed (allowAddRemoveRows is false). |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
409 | CONFLICT | A condition is hiding the field. |
Notes
- Each call adds a row. Send an
Idempotency-Keyif you may retry. - The insert records an entry in the task's activity feed.
Remove a Table Row
Deletes one row by its index. Every row below it moves up one, so the response is the whole table.
DELETE /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/rows/{rowIndex}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a Table field. |
rowIndex | path | integer | Yes | The row's index, from 1. |
Example
DELETE https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28/rows/3
X-API-KEY: your-api-key-here
HTTP/1.1 200 OK
{
"fieldKey": "4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28",
"fieldName": "Line Items",
"columns": 2,
"allowAddRemoveRows": true,
"isDataSetLinked": false,
"rows": [
{
"index": 1,
"isDeletable": false,
"cells": [
{ "row": 1, "column": 1, "value": "Description", "isReadOnly": true, "isRequired": false, "format": "PlainText" },
{ "row": 1, "column": 2, "value": "Amount", "isReadOnly": true, "isRequired": false, "format": "PlainText" }
]
},
{
"index": 2,
"isDeletable": true,
"cells": [
{ "row": 2, "column": 1, "value": "Consulting", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 2, "column": 2, "value": "1200.00", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
}
],
"removedRow": 3
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The Table object, with the removed index in removedRow. |
400 | VALIDATION_ERROR | A path key is not a GUID; rowIndex is not a whole number from 1 upwards, or the table has no such row (field is rowIndex); or the field is not a table (fieldKey). |
403 | FORBIDDEN | The template does not allow this table's rows to be removed, or every cell in the row is read-only (a header row, a label row or a row from a Data Set record). |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
409 | CONFLICT | A condition is hiding the field, or this is the table's last row. A table must keep at least one row, because new rows are copied from an existing one. |
Notes
- Check
isDeletableon the row first; it answers all three row rules in advance. - Retrying is not safe without an
Idempotency-Key: the rows below move up, so the same index then names a different row. - The removal records an entry in the task's activity feed.
Set a Table Cell
Writes one cell, addressed by its row and column. There is no whole-table write.
PUT /v3/checklists/{checklistKey}/tasks/{taskKey}/fields/{fieldKey}/rows/{rowIndex}/cells/{columnIndex}
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
checklistKey | path | string (GUID) | Yes | The checklist's key. |
taskKey | path | string (GUID) | Yes | The task's key. |
fieldKey | path | string (GUID) | Yes | The key of a Table field. |
rowIndex | path | integer | Yes | The cell's row, from 1. |
columnIndex | path | integer | Yes | The cell's column, from 1 to the table's columns. |
Request Body
{
"value": "1350.00"
}
| Field | Type | Required | Description |
|---|---|---|---|
value | string | No | The cell's text, whatever its format says. null, an empty string or leaving it out clears the cell. |
Example
PUT https://api.checkflow.io/v3/checklists/3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14/tasks/8a1d4f27-5c3e-4b9a-a6d2-71e0c9b35f48/fields/4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28/rows/2/cells/2
X-API-KEY: your-api-key-here
Content-Type: application/json
{
"value": "1350.00"
}
HTTP/1.1 200 OK
{
"fieldKey": "4f8d2a6c-3b1e-4c97-a5d0-7e9b1c3f6a28",
"fieldName": "Line Items",
"columns": 2,
"allowAddRemoveRows": true,
"isDataSetLinked": false,
"rows": [
{
"index": 1,
"isDeletable": false,
"cells": [
{ "row": 1, "column": 1, "value": "Description", "isReadOnly": true, "isRequired": false, "format": "PlainText" },
{ "row": 1, "column": 2, "value": "Amount", "isReadOnly": true, "isRequired": false, "format": "PlainText" }
]
},
{
"index": 2,
"isDeletable": true,
"cells": [
{ "row": 2, "column": 1, "value": "Consulting", "isReadOnly": false, "isRequired": true, "format": "PlainText" },
{ "row": 2, "column": 2, "value": "1350.00", "isReadOnly": false, "isRequired": true, "format": "Number" }
]
}
],
"cell": { "row": 2, "column": 2, "value": "1350.00", "isReadOnly": false, "isRequired": true, "format": "Number" },
"changed": true
}
Responses
| Status | Code | When |
|---|---|---|
200 | — | The Table object, with the written cell in cell and changed. |
400 | VALIDATION_ERROR | A path key is not a GUID; the body is not valid JSON; rowIndex or columnIndex is not a whole number from 1 upwards; there is no cell at that position — field is columnIndex when the row exists and rowIndex when it does not; or the field is not a table (fieldKey). |
403 | FORBIDDEN | The cell is read-only. |
404 | CHECKLIST_NOT_FOUND | No checklist with that key in your workspace. |
404 | TASK_NOT_FOUND | The checklist has no task with that key. |
404 | FIELD_NOT_FOUND | The task has no control with that key. |
409 | CONFLICT | A condition is hiding the field. |
Notes
- Sending the value the cell already holds returns
200withchanged: falseand writes nothing. This differs from the field value writes, which write the same value again. - A write that changes the cell records an entry in the task's activity feed.
- Nothing checks the text against the cell's
format, so write numbers and dates the way the rest of the column does.
MCP Equivalent
The task tools call the same code, so they accept the same value shapes and refuse the same things:
get_task_fieldsandset_task_fieldsread and write field values.set_task_fieldstakes a list ofkeyandvalueentries and is the batch write; there is no separate single-field tool and no single-field read.get_task_filesandremove_task_filelist and remove files. There is no MCP tool for adding a file.get_task_table_rows,add_task_table_row,remove_task_table_rowandset_task_table_cellwork on tables.
Table row and column indexes in the MCP tools are the same numbers these routes use, counting from 1.
Related Pages
- Checklist Tasks — completing a task once its fields are filled in, and the task read that carries the same fields.
- Control Types — what each input control is for and how "required" works for each.
- Linking a Data Set to a Control — how Dropdown, Multi-Choice, Sub-Tasks and Table controls come to read from a Data Set.
- Data Sets — the records route that lists the choices a linked field accepts.
- Errors — the error body and every code these routes return.