Data Sets

Endpoints for managing Data Sets — the reference tables that populate Dropdown, Multi-Choice, Sub-Tasks and Table controls in your templates.

These endpoints require API version 2.0.

X-API-VERSION: 2.0

All endpoints are rooted at:

https://app.checkflow.io/api/data-sets

Concepts

TermDescription
Data SetA named table of reference data. Identified by a GUID id, or for System Data Sets by a slug.
FieldA column. Has a type and a position.
RecordA row. Its values object is keyed by field id.
ViewA saved set of filters, sorts and hidden fields.

Data Set Identifier

Everywhere {dataSetId} appears you may pass either:

  • the Data Set's GUID, e.g. 9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11, or
  • a System Data Set's slug, e.g. system-countries.

Source

Every Data Set has a source:

ValueMeaning
organisationA Data Set belonging to your team. Readable and writable.
systemA built-in System Data Set. Read-only — any write returns 403.

Field Types

text, number, date, email, url, boolean.

Note that the True/False field type is called boolean in the API.

Response Codes

CodeMeaning
200Success
201Resource created
204Success, no content returned
400Validation failed — the body contains { "error": "..." } explaining why
401The API key is missing or invalid
403The Data Set is a read-only System Data Set
404The Data Set, field, record or view was not found
409The item is linked to one or more templates — see Conflicts

Conflicts

Deleting a Data Set that is linked to template controls returns 409 with the templates that use it:

{
"error": "This Data Set is linked to one or more Template controls.",
"templates": [
{ "id": "b1f9c5e2-0c9a-4f5b-8a3d-2a1e7f4c9d10", "name": "Client Onboarding" },
{ "id": "7d2a1c44-9e33-4a11-b0f6-58c4e9a1d772", "name": "Quarterly Review" }
]
}

Pass ?force=true to delete anyway. See Deleting a Data Set for what that does to the affected templates.


List Data Sets

Returns every Data Set in your team, plus the built-in System Data Sets.

GET /api/data-sets

Request Headers

HeaderRequiredDescription
X-API-KEYYesYour API key

Example Response

{
"data": [
{
"id": "9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11",
"slug": null,
"name": "Clients",
"source": "organisation",
"description": "Active client accounts",
"fieldCount": 4,
"recordCount": 248,
"createdAt": "2026-05-02T09:14:22",
"updatedAt": "2026-08-01T16:03:47"
},
{
"id": "0f1e6c37-8b52-3d9a-b64e-2c8d5a7f9013",
"slug": "system-countries",
"name": "Countries",
"source": "system",
"description": "ISO 3166-1 countries",
"fieldCount": 4,
"recordCount": 249,
"createdAt": null,
"updatedAt": null
}
]
}

createdAt and updatedAt are always null for System Data Sets.


Create Data Set

Creates a Data Set, optionally with its fields.

POST /api/data-sets

Request Body

{
"name": "Clients",
"description": "Active client accounts",
"fields": [
{ "name": "Name", "type": "text" },
{ "name": "Region", "type": "text" },
{ "name": "Email", "type": "email" }
]
}
FieldTypeRequiredDescription
namestringYesUp to 200 characters.
descriptionstringNoUp to 1,000 characters.
fieldsarrayNoFields to create. If omitted, a single Text field named Name is created.
fields[].namestringYesUp to 200 characters. Must be unique within the Data Set.
fields[].typestringYesOne of text, number, date, email, url, boolean.
fields[].descriptionstringNoFree text, for your own reference.

Example Response

201 Created

{
"id": "9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11",
"slug": null,
"name": "Clients",
"source": "organisation",
"description": "Active client accounts",
"recordCount": 0,
"createdAt": "2026-08-10T11:02:14",
"updatedAt": "2026-08-10T11:02:14",
"fields": [
{ "id": "4c2e...", "name": "Name", "type": "text", "description": null, "position": 0 },
{ "id": "8b71...", "name": "Region", "type": "text", "description": null, "position": 1 },
{ "id": "f39a...", "name": "Email", "type": "email", "description": null, "position": 2 }
],
"views": [
{ "id": "1d5c...", "name": "All Records", "isDefault": true, "filters": [], "sorts": [], "hiddenFields": [] }
]
}

A Data Set created through the API is Unfiled — it is not placed in a Library folder. Move it in the Library if you want it filed.


Get Data Set

Returns a single Data Set with its fields and views. Records are not included — use List Records.

GET /api/data-sets/{dataSetId}

Example Request

GET https://app.checkflow.io/api/data-sets/system-countries
X-API-KEY: your-api-key-here
X-API-VERSION: 2.0

The response is the same shape as Create Data Set.


Update Data Set

Updates the name and description.

PUT /api/data-sets/{dataSetId}

Request Body

{
"name": "Clients (EMEA)",
"description": "Active client accounts in EMEA"
}

Returns the updated Data Set.


Delete Data Set

DELETE /api/data-sets/{dataSetId}

Query Parameters

ParameterTypeRequiredDescription
forceboolNoDefaults to false. When false, a Data Set that is linked to template controls returns 409. When true, it is deleted and the affected links are cleared.

Response Codes

CodeDescription
204Deleted.
403The Data Set is a System Data Set.
409Linked to one or more templates and force was not set.

List Fields

GET /api/data-sets/{dataSetId}/fields

Example Response

{
"data": [
{ "id": "4c2e...", "name": "Name", "type": "text", "description": null, "position": 0 },
{ "id": "8b71...", "name": "Region", "type": "text", "description": null, "position": 1 }
]
}

Create Field

POST /api/data-sets/{dataSetId}/fields

Request Body

{
"name": "Renewal Date",
"type": "date",
"description": "Contract renewal date"
}

Returns 201 with the new field. Existing records gain the field with an empty value.

A Data Set can have at most 50 fields.


Update Field

Renames a field, changes its type, or moves it.

PUT /api/data-sets/{dataSetId}/fields/{fieldId}

Request Body

{
"name": "Renewal Date",
"type": "date",
"position": 3
}
FieldTypeRequiredDescription
namestringYesMust be unique within the Data Set.
typestringYesChanging the type is rejected with 400 if any existing value would become invalid. Changing to text always succeeds.
positionintNoThe field's position, left to right. This is the only way to reorder fields — the web UI does not support it.

Delete Field

DELETE /api/data-sets/{dataSetId}/fields/{fieldId}

Deletes the field and its values in every record.

Returns 400 if the field is the Data Set's only field — a Data Set must always have at least one.

Returns 409 if the field is used as a Display Field or in a Table Column Mapping by a linked template control. Re-point or remove those links first.


List Records

GET /api/data-sets/{dataSetId}/records

Query Parameters

ParameterTypeRequiredDescription
pageintNoDefaults to 1.
pageSizeintNoDefaults to 50. Maximum 200.
viewIdstring (GUID)NoApply a View's filters, sorts and hidden fields. Omit to return every record in creation order.

Example Request

GET https://app.checkflow.io/api/data-sets/9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11/records?page=1&pageSize=50
X-API-KEY: your-api-key-here
X-API-VERSION: 2.0

Example Response

{
"data": [
{
"id": "c81f4a90-6f2b-4b8e-9a71-5d3c0e8b7a24",
"position": 0,
"values": {
"4c2e0b1f-9a34-4c7e-b8d2-77f1a3e05c66": "Northwind Traders",
"8b71d2c5-4e19-42a3-9f0b-6c1e8d4a2b93": "EMEA"
}
}
],
"pagination": { "page": 1, "pageSize": 50, "total": 248, "totalPages": 5 }
}

The values object is keyed by field id. Fields with no value for a record are omitted.


Create Record

POST /api/data-sets/{dataSetId}/records

Request Body

{
"values": {
"4c2e0b1f-9a34-4c7e-b8d2-77f1a3e05c66": "Northwind Traders",
"8b71d2c5-4e19-42a3-9f0b-6c1e8d4a2b93": "EMEA"
}
}

Every value is validated against its field's type. Empty values are always allowed. A record's total cell text must not exceed 5 KB, and a Data Set may hold at most 10,000 records.

Returns 201 with the new record.

Creating a record raises the data_set.record.created webhook event.


Update Record

PUT /api/data-sets/{dataSetId}/records/{recordId}

The body is the same as Create Record. Fields omitted from values are cleared, so send the complete record.

Raises the data_set.record.updated webhook event, whose payload contains only the fields that actually changed.


Delete Record

DELETE /api/data-sets/{dataSetId}/records/{recordId}

Returns 204. Raises the data_set.record.deleted webhook event.

Deleting a record does not affect checklist answers that already reference it — see Answers Are Snapshots.


Bulk Create Records

Adds many records in one call, or atomically replaces the whole contents of a Data Set.

POST /api/data-sets/{dataSetId}/records/bulk

Request Body

{
"mode": "append",
"records": [
{ "values": { "4c2e...": "Northwind Traders", "8b71...": "EMEA" } },
{ "values": { "4c2e...": "Contoso Ltd", "8b71...": "AMER" } }
]
}
FieldTypeRequiredDescription
modestringYesappend adds to the existing records; replace deletes every existing record first.
recordsarrayYesAt least one record.

Returns 201 with the created records.

note

Bulk operations deliberately do not raise per-record webhook events — a 5,000-record replace would otherwise generate 5,000 deliveries.


Bulk Delete Records

DELETE /api/data-sets/{dataSetId}/records/bulk

Request Body

{
"recordIds": [
"c81f4a90-6f2b-4b8e-9a71-5d3c0e8b7a24",
"3e7d21b8-55c4-4d0a-8f19-9b6e2c4a71d5"
]
}

Returns 204.


List Views

GET /api/data-sets/{dataSetId}/views

Example Response

{
"data": [
{
"id": "1d5c8e42-7b90-4a3f-9c15-6e2d0b8a4f37",
"name": "All Records",
"isDefault": true,
"filters": [],
"sorts": [],
"hiddenFields": []
},
{
"id": "62a4f0d7-3c81-4e59-b7a2-0f9c8d15e63b",
"name": "Active Clients",
"isDefault": false,
"filters": [
{ "fieldId": "b3f7...", "operator": "eq", "value": "true" }
],
"sorts": [
{ "fieldId": "4c2e...", "direction": "asc", "position": 0 }
],
"hiddenFields": ["f39a..."]
}
]
}

Create View

POST /api/data-sets/{dataSetId}/views

Request Body

{
"name": "Active Clients",
"filters": [
{ "fieldId": "b3f7...", "operator": "eq", "value": "true" },
{ "fieldId": "8b71...", "operator": "in", "value": "EMEA,AMER" }
],
"sorts": [
{ "fieldId": "4c2e...", "direction": "asc", "position": 0 }
],
"hiddenFields": ["f39a..."]
}
FieldTypeRequiredDescription
namestringYesUp to 200 characters.
filtersarrayNoCombined with AND.
filters[].fieldIdstring (GUID)YesMust be a field of this Data Set.
filters[].operatorstringYesSee the operator table below.
filters[].valuestringConditionalNot used by is_empty / is_not_empty. For in, a comma-separated list.
sorts[].directionstringNoasc (default) or desc.
sorts[].positionintNoSort priority, lowest first.
hiddenFieldsarrayNoField ids to hide from the View.

Filter Operators

OperatorMeaning
eqEquals
neqDoes not equal
containsContains the text
not_containsDoes not contain the text
starts_withStarts with the text
ends_withEnds with the text
gtGreater than
gteGreater than or equal to
ltLess than
lteLess than or equal to
is_emptyThe cell has no value
is_not_emptyThe cell has a value
inMatches any value in a comma-separated list

An unrecognised operator returns 400.

A Data Set can have at most 20 Views. Returns 201 with the new View.


Get View

GET /api/data-sets/{dataSetId}/views/{viewId}

Update View

PUT /api/data-sets/{dataSetId}/views/{viewId}

The body is the same as Create View and replaces the View's filters, sorts and hidden fields entirely.

The default All Records View cannot be renamed.


Delete View

DELETE /api/data-sets/{dataSetId}/views/{viewId}

Returns 204. The All Records View cannot be deleted.

Deleting a View that template controls are linked to is allowed — those templates will show a link warning until they are re-pointed. See Warnings About Broken Links.


Import CSV

Creates a Data Set from a CSV file, or replaces every record in an existing one.

POST /api/data-sets/import

The request is multipart/form-data.

Form fieldTypeRequiredDescription
filefileYesThe CSV file. Maximum 5 MB.
modestringNocreate (default) or replace.
dataSetIdstringConditionalRequired when mode is replace.
namestringNoThe Data Set name. Defaults to the uploaded file's name without its extension.
descriptionstringNoUp to 1,000 characters.

Example Request

POST https://app.checkflow.io/api/data-sets/import
X-API-KEY: your-api-key-here
X-API-VERSION: 2.0
Content-Type: multipart/form-data
file=@clients.csv
name=Clients
mode=create

Example Response

{
"status": "complete",
"dataSet": {
"id": "9a3b6f88-1f2c-4a7d-9c62-1d7f5b0e4a11",
"name": "Clients",
"source": "organisation",
"recordCount": 248,
"fields": [],
"views": []
}
}

The import is synchronous — the response is returned once it has completed. There is no job to poll.

The whole file must be valid or nothing is imported. See Importing and Exporting CSV for column type detection, format rules and the full list of validation messages.


Export CSV

GET /api/data-sets/{dataSetId}/export

Query Parameters

ParameterTypeRequiredDescription
viewIdstring (GUID)NoExport a specific View. Omit to use the default View.

Returns a text/csv file encoded as UTF-8 with a byte-order mark, named <data-set>-<view>-<date>.csv.

Only the View's visible columns are included, and only the records that pass its filters, in its sort order.

Exporting a System Data Set returns 403.


Webhooks

Record changes made through the API — or in the web UI — can be delivered to your own endpoint:

  • data_set.record.created
  • data_set.record.updated
  • data_set.record.deleted

See Webhooks for subscription management and payload shapes.

Related Pages