Skip to main content

Webhook Events

A webhook subscription listens for one of the nine events on this page. Each section says precisely what fires the event and what looks as if it should but does not, then gives the body CheckFlow posts. Subscribing, delivery, retries and signature verification are the same for every event and are described once, on Webhooks.

EventFires whenScopesPayload
new_checklistA checklist is started from a template.TemplateChecklist
task_completedA task is completed.Task, Template, WorkspaceTask
file_uploadedA file is uploaded to a File Upload control.FieldFile
checklist_completedA checklist becomes complete.Template, WorkspaceChecklist
comment_createdA comment is written on a task.Task, WorkspaceComment
task_assignedA task is given to somebody who did not have it.Task, Template, WorkspaceAssignment
data_set.record.createdA Data Set record is added.WorkspaceData Set record
data_set.record.updatedA Data Set record's values change.WorkspaceData Set record
data_set.record.deletedA Data Set record is deleted.WorkspaceData Set record

A v2 subscription and a v3 subscription to the same event receive the same body: the payload is built once per event and posted to every matching subscription. The only difference is the CF-Signature header, which a subscription without a secret does not get.

Reading a Payload​

The payloads come in two families, and they are formatted differently:

  • new_checklist, task_completed, file_uploaded and checklist_completed send the checklist, task and file shapes the v2 API has always sent. They are indented JSON, with property names prefixed by the object they belong to (checklistName, taskKey), and they contain no eventType property. Their timestamps are UTC written with an offset, such as 2026-09-15T09:40:12+00:00. A property with no value is sent as null, not left out.
  • comment_created, task_assigned and the three Data Set events are single-line JSON that starts with an eventType property. A property with no value is sent as null.

Both families are written with JSON escaping of characters outside ASCII and of HTML-sensitive characters: an em dash arrives as —, & as &, < and > as < and >, a double quote inside a string as ". Any JSON parser turns these back into the characters, but the escaped form is what the signature was computed over, so verify the raw bytes before parsing. The examples on this page show the payloads exactly as sent, except that single-line payloads are shown indented for reading.

This page does not follow the rest of the v3 API's conventions — camelCase names without prefixes, keys rather than numeric ids, timestamps ending in Z, absent rather than null — because the four older payloads cannot change without breaking the receivers built on them. Read a payload as a notification and use the keys in it with the v3 routes, such as GET /v3/checklists/{key}, when you need the full, current picture.

Shared Payload Objects​

The Checklist Payload​

new_checklist and checklist_completed send the whole checklist, with every task on it and each task's fields and comments.

FieldTypeDescription
checklistIdintegerThe checklist's numeric id.
checklistKeystring (GUID)The checklist's key — the one the v3 checklist routes take.
checklistNamestringThe checklist's name.
checklistUrlstringThe checklist's page in the app.
checklistScheduledDateTimestring or nullWhen a scheduled checklist was scheduled for; null otherwise.
checklistStartDateTimestring or nullWhen the checklist was started.
checklistEndDateTimestring or nullWhen the checklist was completed; null while it is open.
checklistCreatedByNamestringWho started it. CheckFlow Scheduler for a checklist started by a schedule.
checklistCreatedByEmailstringTheir email address. support@checkflow.io for a scheduled checklist.
checklistIsSharedbooleanWhether the checklist is shared by link.
checklistSharedUrlstring or nullThe share link, or null when there is none.
checklistIsArchivedbooleanWhether the checklist is archived.
templateTemplateThe template it was started from.
tasksarray of Checklist TaskEvery task on the checklist, in order, headings included.

Each entry in tasks:

FieldTypeDescription
taskIdintegerThe task's numeric id on this checklist.
taskKeystring (GUID)The task's key. This is the template task's key, so it is the same on every checklist started from the template — see Scope Keys Are Template Keys.
taskNamestringThe task's name.
taskIsHeadingbooleanWhether the entry is a heading rather than a task.
taskIsCurrentlyHaltedbooleanWhether the task is waiting on an earlier task.
taskIsCurrentlyHiddenbooleanWhether conditional logic currently hides the task.
taskDueDateTimestring or nullThe task's due date.
taskCompletedDateTimestring or nullWhen it was completed or marked Not Applicable.
taskCompletedByNamestring or nullWho completed it.
taskCompletedByEmailstring or nullTheir email address.
assigneesarray of AssigneeWho the task is assigned to.
fieldsarrayThe task's input controls and their values — see Fields in a Payload.
commentsarray of CommentThe comments on the task.

A task on the checklist payload has no taskUrl and no tags; the Task Payload has both.

The Task Payload​

task_completed sends one task, with its checklist and template.

FieldTypeDescription
taskIdintegerThe task's numeric id.
taskKeystring (GUID)The task's key — the template task's key for a checklist task, the task's own key for a standalone task.
taskNamestringThe task's name.
taskUrlstringThe task in the app: its place on its checklist, or, for a standalone task that is not attached to a checklist, the task in the Tasks grid.
taskIsHeadingbooleanWhether the task is a heading.
taskIsCurrentlyHaltedbooleanWhether the task is waiting on an earlier task.
taskIsCurrentlyHiddenbooleanWhether conditional logic currently hides the task.
taskDueDateTimestring or nullThe task's due date.
taskCompletedDateTimestring or nullWhen it was completed.
taskCompletedByNamestring or nullWho completed it.
taskCompletedByEmailstring or nullTheir email address.
assigneesarray of AssigneeWho the task is assigned to.
fieldsarrayThe task's input controls and their values — see Fields in a Payload.
commentsarray of CommentThe comments on the task.
tagsarray of TagThe task's tags.
checklistChecklist SummaryThe checklist the task is on.
templateTemplateThe checklist's template.

A standalone task that is not attached to a checklist still has checklist and template objects, with every property present and empty: checklistId and templateId are 0, templateVersion is 0, checklistIsShared is false, and everything else is null. Test checklist.checklistKey for null to tell the two cases apart. A standalone task attached to a checklist reports that checklist and its template.

The Checklist Summary Object​

The checklist object inside the task and file payloads. It has the first eleven properties of the Checklist Payload — checklistId to checklistSharedUrl — and not checklistIsArchived, template or tasks; the template is a sibling object instead.

The Template Object​

FieldTypeDescription
templateIdintegerThe template's numeric id.
templateKeystring (GUID)The template's key — the one a Template scope names.
templateNamestringThe template's name.
templateUrlstringThe template's page in the app.
templateDescriptionstringThe template's description.
templateVersionintegerThe template version the checklist was started from.
templateCreatedDateTimestringWhen that template version was created.

The Assignee Object​

FieldTypeDescription
assigneeIdintegerThe member's or group's id — the same ids as Members and Groups.
assigneeTypestringTeamMember or Group.
assigneeNamestringThe member's or group's name.

The Comment Object​

FieldTypeDescription
commentIDintegerThe comment's id. Note the capital ID.
commentHtmlstringThe comment as HTML, as it was typed.
commentDateTimestringWhen it was written.

The Tag Object​

FieldTypeDescription
tagKeystringThe tag's key.
tagNamestringThe tag's name.
assignmentKeystringThe key of what the tag is on.
assignmentTypestringTask.
parentKeystring or nullA related key, or null.

Fields in a Payload​

Fields are the task's input controls (see Control Types). In these four payloads each field is an object with a single property, and the property's name is built from the control's type and its label: the type name below, an underscore, then the label, both lower-cased with spaces replaced by underscores. A Short Text control labelled Invoice Number becomes short_text_invoice_number. An unlabelled control is named from Unlabelled <type> Content at Position <n> in the same way.

ControlProperty name startsValue
Short Textshort_text_The text, or null.
Long Textlong_text_The text, or null.
E-Mailemail_input_The address, or null.
Websitewebsite_The URL, or null.
Date & Timedate_The date, or null. In the task payload it has an offset (2026-09-12T00:00:00+00:00); in the checklist payload it has none (2026-09-12T00:00:00).
Drop-Downdrop_down_The selected option's text, or null.
Multi-Choicemulti_choice_drop_down_An array with one object per option, each holding one property — the field's name, _, and the option's text in the same form — set to true or false.
Sub-Taskssub_tasks_An array with one object per sub-task, named in the same way as Multi-Choice options, set to whether it is ticked.
File Uploadfile_An array with one object per uploaded file, holding <name>_file_<n>_name, <name>_file_<n>_content_type and <name>_file_<n>_url, where <n> counts from 0.
Filefile_upload_The same array, for the files attached in the template.
Tabletable_An array with one object per filled cell: rowIndex, columnIndex (both from 1), value and isReadOnly.
Mail To—An empty object {}.

Other controls — including Members, Linked Checklist and the content controls — do not appear in fields.

warning

The property names change when somebody edits a control's label or an option's text, and a label with punctuation keeps it (Invoice # becomes short_text_invoice_#). Two controls with the same type and label on one task produce the same name. If you need a stable reference to a field, read the task through Task Fields, which identifies fields by key.

new_checklist​

Fires when a checklist is started from a template. A typical receiver opens a matching record in another system.

new_checklist

When It Fires​

Once for each checklist started from the template the subscription is scoped to, however it was started: in the app, through the v2 or v3 API or the MCP server, by a schedule, or by a Linked Checklist control creating one automatically.

It does not fire when an existing checklist is upgraded to a newer version of its template. It is about a template only: there is no workspace-wide form, so to hear about every new checklist you need one subscription per template.

Payload Schema​

The Checklist Payload, as it stands when the event is processed — usually moments after the checklist was created. checklistEndDateTime is null and most fields are empty, apart from any values filled in when the checklist was created.

Example Payload​

{
"checklistId": 48213,
"checklistKey": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistName": "Invoice Review — INV-2041",
"checklistUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistScheduledDateTime": null,
"checklistStartDateTime": "2026-09-15T08:58:31+00:00",
"checklistEndDateTime": null,
"checklistCreatedByName": "Priya Patel",
"checklistCreatedByEmail": "priya.patel@acme.example",
"checklistIsShared": false,
"checklistSharedUrl": null,
"checklistIsArchived": false,
"template": {
"templateId": 312,
"templateKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"templateName": "Invoice Review",
"templateUrl": "https://app.checkflow.io/Template/Index?templateId=312",
"templateDescription": "Check, approve and file a supplier invoice.",
"templateVersion": 4,
"templateCreatedDateTime": "2026-02-03T10:15:00+00:00"
},
"tasks": [
{
"taskId": 901,
"taskKey": "a41f6b2d-9c3e-4d7a-8b15-6e0f2c9d3a58",
"taskName": "Check invoice details",
"taskIsHeading": false,
"taskIsCurrentlyHalted": false,
"taskIsCurrentlyHidden": false,
"taskDueDateTime": "2026-09-17T17:00:00+00:00",
"taskCompletedDateTime": null,
"taskCompletedByName": null,
"taskCompletedByEmail": null,
"assignees": [
{
"assigneeId": 12,
"assigneeType": "Group",
"assigneeName": "Finance Team"
}
],
"fields": [
{
"short_text_invoice_number": "INV-2041"
},
{
"date_invoice_date": null
},
{
"file_signed_invoice": []
}
],
"comments": []
},
{
"taskId": 902,
"taskKey": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36",
"taskName": "Approve invoice",
"taskIsHeading": false,
"taskIsCurrentlyHalted": true,
"taskIsCurrentlyHidden": false,
"taskDueDateTime": null,
"taskCompletedDateTime": null,
"taskCompletedByName": null,
"taskCompletedByEmail": null,
"assignees": [
{
"assigneeId": 1041,
"assigneeType": "TeamMember",
"assigneeName": "Sarah Chen"
}
],
"fields": [
{
"drop_down_decision": null
},
{
"sub_tasks_checks": [
{
"sub_tasks_checks_po_matched": false
},
{
"sub_tasks_checks_vat_correct": false
}
]
}
],
"comments": []
}
]
}

Delivery and Retries​

See Receiving Deliveries. The body grows with the number of tasks and fields on the template.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. A subscription without a secret receives no signature, and nothing in the delivery proves it came from CheckFlow; confirm the checklist with GET /v3/checklists/{key} before acting on it. The body has no eventType and is the same shape as checklist_completed, so give this subscription a target URL of its own.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "new_checklist",
"targetUrl": "https://hooks.acme.example/checkflow/new-checklist",
"scope": {
"type": "Template",
"key": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14"
}
}

See Create a Webhook.

  • checklist_completed — the other end of the checklist's life, with the same payload shape.
  • task_assigned — fires separately for the people given tasks on the new checklist.

task_completed​

Fires when a task is completed. A typical receiver moves something on in another system when a particular step is done.

task_completed

When It Fires​

Each time a task is completed, in the app, through the v2 or v3 API or through the MCP server — checklist tasks and standalone tasks alike. Completing a task, un-completing it and completing it again fires twice.

Which subscriptions receive it depends on scope:

ScopeReceives
Task with a template task's keyThat task, completed on any checklist started from the template.
Task with a standalone task's keyThat one standalone task.
TemplateEvery task completed on a checklist started from the template, including standalone tasks attached to such a checklist.
WorkspaceEvery task completed anywhere in the workspace, including standalone tasks.

A subscription that matches in more than one way receives the event once.

It does not fire when:

  • a task is marked Not Applicable — even though that stamps the task's completion time;
  • a task is un-completed — there is no task_uncompleted event;
  • a checklist is upgraded to a newer template version and the tasks that were already complete are carried across;
  • the task has been un-completed again by the time the event is processed, which is normally within moments. The event is dropped rather than sent about a task that is no longer complete.

A standalone task that is not attached to a checklist has no template, so a Template-scoped subscription never receives it.

Payload Schema​

The Task Payload, as the task stands when the event is processed.

Example Payload​

{
"taskId": 902,
"taskKey": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36",
"taskName": "Approve invoice",
"taskUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54&checklistTaskId=902",
"taskIsHeading": false,
"taskIsCurrentlyHalted": false,
"taskIsCurrentlyHidden": false,
"taskDueDateTime": "2026-09-18T17:00:00+00:00",
"taskCompletedDateTime": "2026-09-15T09:40:12+00:00",
"taskCompletedByName": "Sarah Chen",
"taskCompletedByEmail": "sarah.chen@acme.example",
"assignees": [
{
"assigneeId": 1041,
"assigneeType": "TeamMember",
"assigneeName": "Sarah Chen"
}
],
"fields": [
{
"drop_down_decision": "Approved"
},
{
"sub_tasks_checks": [
{
"sub_tasks_checks_po_matched": true
},
{
"sub_tasks_checks_vat_correct": true
}
]
}
],
"comments": [
{
"commentID": 5521,
"commentHtml": "<p>Approved for payment.</p>",
"commentDateTime": "2026-09-15T09:39:50+00:00"
}
],
"tags": [
{
"tagKey": "e4c1a7f2-8b3d-4a95-9c60-1f2e7d8b5a36",
"tagName": "urgent",
"assignmentKey": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36",
"assignmentType": "Task",
"parentKey": null
}
],
"checklist": {
"checklistId": 48213,
"checklistKey": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistName": "Invoice Review — INV-2041",
"checklistUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistScheduledDateTime": null,
"checklistStartDateTime": "2026-09-15T08:58:31+00:00",
"checklistEndDateTime": null,
"checklistCreatedByName": "Priya Patel",
"checklistCreatedByEmail": "priya.patel@acme.example",
"checklistIsShared": false,
"checklistSharedUrl": null
},
"template": {
"templateId": 312,
"templateKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"templateName": "Invoice Review",
"templateUrl": "https://app.checkflow.io/Template/Index?templateId=312",
"templateDescription": "Check, approve and file a supplier invoice.",
"templateVersion": 4,
"templateCreatedDateTime": "2026-02-03T10:15:00+00:00"
}
}

checklistEndDateTime is null here even though this was the last task: the checklist's completion is a separate event, checklist_completed.

Delivery and Retries​

See Receiving Deliveries. A Workspace subscription on a busy workspace receives one delivery per completed task, so completing many tasks at once produces a burst.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. Without a secret, confirm the task through the API before acting on it. The body has no eventType.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "task_completed",
"targetUrl": "https://hooks.acme.example/checkflow/invoice-approved",
"scope": {
"type": "Task",
"key": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36"
}
}

See Create a Webhook.

  • checklist_completed — fires as well when the completed task was the checklist's last outstanding one.
  • file_uploaded — fires for files as they are uploaded, before the task is completed.

file_uploaded​

Fires when a file is uploaded to a File Upload control. A typical receiver copies the file into a document store.

file_uploaded

When It Fires​

Once for each file uploaded to the File Upload control the subscription is scoped to, on any checklist started from its template, whether uploaded in the app or through the v3 API or MCP server. Uploading three files fires three events.

It does not fire when:

  • a file is attached to a comment;
  • a file is removed from the control;
  • the file has already been removed by the time the event is processed — the event is dropped.

It is about one control only. There is no workspace-wide or template-wide form, and the scope key must be the key of a File Upload control — the key of any other control is refused.

Payload Schema​

FieldTypeDescription
idintegerThe File Upload control's numeric id on this checklist.
fileUploadKeystring (GUID)The control's key — the same template-level key the subscription's Field scope names.
fileUploadLabelstringThe control's label.
minFilesRequiredintegerThe control's minimum number of files.
maxFilesRequiredintegerThe control's maximum number of files.
filesarrayThe file that was uploaded — always exactly one entry.
files[].fileIdintegerThe file's id.
files[].originalFileNamestringThe file's name as uploaded.
files[].fileTypestringThe file's content type.
files[].urlstringWhere the stored file is.
files[].uploadedByIdinteger or nullThe id of the member who uploaded it.
files[].uploadedByNamestring or nullTheir name.
files[].uploadedByEmailstring or nullTheir email address.
files[].uploadedDateTimestring or nullWhen it was uploaded.
taskobjectThe task the control is on: taskId, taskKey, taskName, taskUrl, taskDueDateTime, taskCompletedDateTime, taskCompletedByName and taskCompletedByEmail, as on the Task Payload.
checklistChecklist SummaryThe checklist. Empty, as described under the Task Payload, for an unattached standalone task.
templateTemplateThe checklist's template. Empty in the same case.

Example Payload​

{
"id": 7310,
"fileUploadKey": "5e9b2c71-0d4a-4f86-a3c2-8b17e6d0f934",
"fileUploadLabel": "Signed invoice",
"minFilesRequired": 1,
"maxFilesRequired": 3,
"files": [
{
"fileId": 66120,
"originalFileName": "INV-2041-signed.pdf",
"fileType": "application/pdf",
"url": "https://files.example/acme/66120/INV-2041-signed.pdf",
"uploadedById": 1043,
"uploadedByName": "James Okafor",
"uploadedByEmail": "james.okafor@acme.example",
"uploadedDateTime": "2026-09-15T09:05:48+00:00"
}
],
"task": {
"taskId": 901,
"taskKey": "a41f6b2d-9c3e-4d7a-8b15-6e0f2c9d3a58",
"taskName": "Check invoice details",
"taskUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54&checklistTaskId=901",
"taskDueDateTime": "2026-09-17T17:00:00+00:00",
"taskCompletedDateTime": null,
"taskCompletedByName": null,
"taskCompletedByEmail": null
},
"checklist": {
"checklistId": 48213,
"checklistKey": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistName": "Invoice Review — INV-2041",
"checklistUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistScheduledDateTime": null,
"checklistStartDateTime": "2026-09-15T08:58:31+00:00",
"checklistEndDateTime": null,
"checklistCreatedByName": "Priya Patel",
"checklistCreatedByEmail": "priya.patel@acme.example",
"checklistIsShared": false,
"checklistSharedUrl": null
},
"template": {
"templateId": 312,
"templateKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"templateName": "Invoice Review",
"templateUrl": "https://app.checkflow.io/Template/Index?templateId=312",
"templateDescription": "Check, approve and file a supplier invoice.",
"templateVersion": 4,
"templateCreatedDateTime": "2026-02-03T10:15:00+00:00"
}
}

Delivery and Retries​

See Receiving Deliveries. The payload carries a link to the file, not the file itself.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. Without a secret, do not fetch a URL from an unverified payload; read the file through the API instead. The body has no eventType.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "file_uploaded",
"targetUrl": "https://hooks.acme.example/checkflow/signed-invoice",
"scope": {
"type": "Field",
"key": "5e9b2c71-0d4a-4f86-a3c2-8b17e6d0f934"
}
}

See Create a Webhook.

  • task_completed — fires when the task holding the control is completed, with every file on it in fields.

checklist_completed​

Fires when a checklist becomes complete. A typical receiver closes the matching record in another system.

checklist_completed

When It Fires​

When a checklist's end date is set — the one moment a checklist becomes complete, however it got there: its last outstanding task was completed, a standalone task holding it up was detached, or it was marked complete in the app or through the API.

It does not fire when a checklist is reopened; there is no checklist_uncompleted event. A checklist that is reopened and completed again fires a second time. A checklist with no tasks other than headings is never counted as complete by attaching or detaching tasks.

Payload Schema​

The Checklist Payload, with checklistEndDateTime set. It is the same shape as new_checklist.

Example Payload​

{
"checklistId": 48213,
"checklistKey": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistName": "Invoice Review — INV-2041",
"checklistUrl": "https://app.checkflow.io/Checklist/Index?checklistKey=c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"checklistScheduledDateTime": null,
"checklistStartDateTime": "2026-09-15T08:58:31+00:00",
"checklistEndDateTime": "2026-09-15T09:40:12+00:00",
"checklistCreatedByName": "Priya Patel",
"checklistCreatedByEmail": "priya.patel@acme.example",
"checklistIsShared": false,
"checklistSharedUrl": null,
"checklistIsArchived": false,
"template": {
"templateId": 312,
"templateKey": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"templateName": "Invoice Review",
"templateUrl": "https://app.checkflow.io/Template/Index?templateId=312",
"templateDescription": "Check, approve and file a supplier invoice.",
"templateVersion": 4,
"templateCreatedDateTime": "2026-02-03T10:15:00+00:00"
},
"tasks": [
{
"taskId": 901,
"taskKey": "a41f6b2d-9c3e-4d7a-8b15-6e0f2c9d3a58",
"taskName": "Check invoice details",
"taskIsHeading": false,
"taskIsCurrentlyHalted": false,
"taskIsCurrentlyHidden": false,
"taskDueDateTime": "2026-09-17T17:00:00+00:00",
"taskCompletedDateTime": "2026-09-15T09:07:03+00:00",
"taskCompletedByName": "James Okafor",
"taskCompletedByEmail": "james.okafor@acme.example",
"assignees": [
{
"assigneeId": 12,
"assigneeType": "Group",
"assigneeName": "Finance Team"
}
],
"fields": [
{
"short_text_invoice_number": "INV-2041"
},
{
"date_invoice_date": "2026-09-12T00:00:00"
},
{
"file_signed_invoice": [
{
"file_signed_invoice_file_0_name": "INV-2041-signed.pdf",
"file_signed_invoice_file_0_content_type": "application/pdf",
"file_signed_invoice_file_0_url": "https://files.example/acme/66120/INV-2041-signed.pdf"
}
]
}
],
"comments": []
},
{
"taskId": 902,
"taskKey": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36",
"taskName": "Approve invoice",
"taskIsHeading": false,
"taskIsCurrentlyHalted": false,
"taskIsCurrentlyHidden": false,
"taskDueDateTime": "2026-09-18T17:00:00+00:00",
"taskCompletedDateTime": "2026-09-15T09:40:12+00:00",
"taskCompletedByName": "Sarah Chen",
"taskCompletedByEmail": "sarah.chen@acme.example",
"assignees": [
{
"assigneeId": 1041,
"assigneeType": "TeamMember",
"assigneeName": "Sarah Chen"
}
],
"fields": [
{
"drop_down_decision": "Approved"
},
{
"sub_tasks_checks": [
{
"sub_tasks_checks_po_matched": true
},
{
"sub_tasks_checks_vat_correct": true
}
]
}
],
"comments": [
{
"commentID": 5521,
"commentHtml": "<p>Approved for payment.</p>",
"commentDateTime": "2026-09-15T09:39:50+00:00"
}
]
}
]
}

Delivery and Retries​

See Receiving Deliveries. When the last task is completed, task_completed and checklist_completed are separate events and can arrive in either order.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. Without a secret, confirm the checklist through the API before acting on it. The body has no eventType and is the same shape as new_checklist, so give this subscription a target URL of its own; a non-null checklistEndDateTime is the only thing in the body that tells the two apart.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "checklist_completed",
"targetUrl": "https://hooks.acme.example/checkflow/invoice-review-done",
"scope": {
"type": "Template",
"key": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14"
}
}

Leave out scope to receive every checklist completed in the workspace. A Task scope is refused.

comment_created​

Fires when somebody writes a comment on a task. A typical receiver copies the comment into a ticket or a chat channel.

comment_created

When It Fires​

Once for each new comment on a checklist task or a standalone task, whether written in the app, through the v2 or v3 API or through the MCP server. A Task scope with a template task's key receives comments on that task on every checklist started from the template; with a standalone task's key, comments on that task. A Workspace scope receives every comment in the workspace.

It does not fire when a comment is edited or deleted. A Template scope is refused for this event, because a comment does not carry its template.

Payload Schema​

FieldTypeDescription
eventTypestringcomment_created.
commentIdintegerThe comment's id. There is no GUID key for a comment.
createdDateTimestringWhen the comment was written, in UTC. Written without a zone designator or offset, such as 2026-09-15T09:39:50.217.
createdByIdintegerThe id of the member who wrote it.
createdByNamestring or nullTheir full name.
createdByEmailstring or nullTheir email address.
htmlstringThe comment as HTML, exactly as it was typed.
taskobjectThe task: id (integer), key (GUID — the template task's key, or a standalone task's own key) and name.
checklistobject or nullThe checklist: id, key and name. null for a standalone task that is not attached to a checklist.
warning

html is user-written markup going into your system. Sanitise it before displaying it anywhere.

Example Payload​

Sent as one line; shown indented here.

{
"eventType": "comment_created",
"commentId": 5521,
"createdDateTime": "2026-09-15T09:39:50.217",
"createdById": 1041,
"createdByName": "Sarah Chen",
"createdByEmail": "sarah.chen@acme.example",
"html": "<p>Approved for payment.</p>",
"task": {
"id": 902,
"key": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36",
"name": "Approve invoice"
},
"checklist": {
"id": 48213,
"key": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"name": "Invoice Review — INV-2041"
}
}

Delivery and Retries​

See Receiving Deliveries. A workspace-wide subscription receives every comment anybody writes.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. This event can only be subscribed to through v3, but a subscription created over MCP has no secret you can see until it is rotated.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "comment_created",
"targetUrl": "https://hooks.acme.example/checkflow/approval-comments",
"scope": {
"type": "Task",
"key": "6d3c9e1f-4a7b-4e52-b0d8-2c5f9a1e7b36"
}
}

See Create a Webhook.

  • task_completed — its payload includes the task's comments so far, as comments.

task_assigned​

Fires when a task is given to somebody who did not have it. A typical receiver notifies that person in another system.

task_assigned

When It Fires​

Once for each person newly responsible for an open task. Assigning a group sends one event for each of its members who did not already have the task; assigning two people sends two events. It fires wherever the assignment was made — in the app, through the API or MCP server — and for checklist tasks and standalone tasks alike.

It does not fire when:

  • the assignees are saved again unchanged;
  • somebody is removed from a task — there is no task_unassigned event;
  • the task is already complete;
  • somebody already had the task through a group and is now assigned directly, or the other way round.

It fires for a deactivated member, although they are not sent the usual assignment email.

Payload Schema​

FieldTypeDescription
eventTypestringtask_assigned.
assignedDateTimestringWhen the assignment was processed, in UTC, ending in Z.
assignedToIdintegerThe id of the member now responsible.
assignedToNamestring or nullTheir full name.
assignedToEmailstring or nullTheir email address.
taskobjectid (integer), key (GUID), name, and dueDateTime — the due date in UTC without a zone designator, or null.
checklistobject or nullid, key, name and template (key and name). null for a standalone task that is not attached to a checklist.

The payload does not include the task's fields, so no form answers leave the workspace with it.

Example Payload​

Sent as one line; shown indented here.

{
"eventType": "task_assigned",
"assignedDateTime": "2026-09-15T09:12:44.1873526Z",
"assignedToId": 1043,
"assignedToName": "James Okafor",
"assignedToEmail": "james.okafor@acme.example",
"task": {
"id": 901,
"key": "a41f6b2d-9c3e-4d7a-8b15-6e0f2c9d3a58",
"name": "Check invoice details",
"dueDateTime": "2026-09-17T17:00:00"
},
"checklist": {
"id": 48213,
"key": "c7a91e3d-5f2b-4c8e-a6d1-9b0f3e7c2a54",
"name": "Invoice Review — INV-2041",
"template": {
"key": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14",
"name": "Invoice Review"
}
}
}

Delivery and Retries​

See Receiving Deliveries. Assigning a large group sends one delivery per member.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "task_assigned",
"targetUrl": "https://hooks.acme.example/checkflow/assignments",
"scope": {
"type": "Template",
"key": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14"
}
}

It accepts the same three scopes as task_completed. A standalone task that is not attached to a checklist has no template, so a Template scope never receives it.

data_set.record.created​

Fires when a record is added to a Data Set. A typical receiver mirrors the record into another system.

data_set.record.created

When It Fires​

When one record is added — on the Data Set's page in the app, or through the single-record create route of the v2 or v3 API or the MCP server. It fires for every Data Set in the workspace; the three Data Set events accept only a Workspace scope, so filter on dataSetId at your end.

It does not fire for records added in bulk — the bulk create routes and CSV import or replace add records without any event. A webhook is therefore not a reliable way to mirror a Data Set that is maintained by import.

Payload Schema​

FieldTypeDescription
eventTypestringdata_set.record.created.
dataSetIdstring (GUID)The Data Set's key — the one the v3 Data Set routes take.
dataSetNamestringThe Data Set's name.
recordIdstring (GUID)The new record's key.
valuesobjectThe record's values, keyed by field key. Every value is a string. A field with no value is left out.

Example Payload​

Sent as one line; shown indented here.

{
"eventType": "data_set.record.created",
"dataSetId": "9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11",
"dataSetName": "Suppliers",
"recordId": "c81f4a90-6f2b-4b8e-9a71-5d3c0e8b7a24",
"values": {
"4c2e0b1f-9a34-4c7e-b8d2-77f1a3e05c66": "Northwind Traders",
"8b71d2c5-4e19-42a3-9f0b-6c1e8d4a2b93": "EMEA",
"2f6a9d13-5b8e-4c07-a1d4-93e2c7b0f865": "true"
}
}

Look up what each field key means with GET /v3/data-sets/{dataSetKey}.

Delivery and Retries​

See Receiving Deliveries.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. Without a secret, read the record back through the API before acting on it.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "data_set.record.created",
"targetUrl": "https://hooks.acme.example/checkflow/supplier-added"
}

No scope: the Data Set events are workspace-wide only.

data_set.record.updated​

Fires when a Data Set record's values change.

data_set.record.updated

When It Fires​

When one record is saved with at least one value different from before — on the Data Set's page in the app, or through the single-record update route of the v2 or v3 API or the MCP server. It fires for every Data Set in the workspace.

It does not fire when a record is saved with no actual change, or when records are changed in bulk or by a CSV import.

Payload Schema​

FieldTypeDescription
eventTypestringdata_set.record.updated.
dataSetIdstring (GUID)The Data Set's key.
dataSetNamestringThe Data Set's name.
recordIdstring (GUID)The record's key.
changesobjectOnly the fields that changed, keyed by field key. Each holds before and after, both strings, and null when the field was or is now empty.

Example Payload​

Sent as one line; shown indented here.

{
"eventType": "data_set.record.updated",
"dataSetId": "9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11",
"dataSetName": "Suppliers",
"recordId": "c81f4a90-6f2b-4b8e-9a71-5d3c0e8b7a24",
"changes": {
"8b71d2c5-4e19-42a3-9f0b-6c1e8d4a2b93": {
"before": "EMEA",
"after": "AMER"
},
"d05e7a3c-1f9b-4e26-8c4a-6b2f0e9d7a18": {
"before": null,
"after": "accounts@northwind.example"
}
}
}

Delivery and Retries​

See Receiving Deliveries.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "data_set.record.updated",
"targetUrl": "https://hooks.acme.example/checkflow/supplier-changed"
}

data_set.record.deleted​

Fires when a Data Set record is deleted.

data_set.record.deleted

When It Fires​

Once for each record deleted — including each record in a bulk delete, whether made on the Data Set's page in the app or through the bulk delete routes of the API. It fires for every Data Set in the workspace.

It does not fire for records removed when a CSV import replaces a Data Set's records, or when a whole Data Set is deleted.

Payload Schema​

FieldTypeDescription
eventTypestringdata_set.record.deleted.
dataSetIdstring (GUID)The Data Set's key.
dataSetNamestringThe Data Set's name.
recordIdstring (GUID)The deleted record's key.

The record's values are not included; keep your own copy if you need them.

Example Payload​

Sent exactly as shown, on one line:

{"eventType":"data_set.record.deleted","dataSetId":"9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11","dataSetName":"Suppliers","recordId":"c81f4a90-6f2b-4b8e-9a71-5d3c0e8b7a24"}

This is the body used in the worked signature example.

Delivery and Retries​

See Receiving Deliveries. Deleting many records at once sends one delivery per record.

Verification​

Signed with CF-Signature when the subscription has a secret — see Verifying Signatures. An unverified delete notification should not delete anything at your end until the record's absence is confirmed through the API.

Subscribing​

POST https://api.checkflow.io/v3/webhooks
X-API-KEY: your-api-key-here
Content-Type: application/json

{
"eventType": "data_set.record.deleted",
"targetUrl": "https://hooks.acme.example/checkflow/supplier-deleted"
}
  • Webhooks — creating subscriptions, delivery and retries, and verifying CF-Signature.
  • Task Fields — reading a task's field values by key rather than by the generated names in these payloads.
  • Data Sets — resolving the field keys in a Data Set payload.
  • Control Types — the controls whose values appear in fields.