Dataset Management¶
(introduced: version 2022.3)
⚠️ In this API and in the related ODK XForms specification, collections of
Entitiesare referred to asDatasets. The term "Entity List" is used for this concept in the Central frontend UI, user documentation, and all other text intended for end users who are not developers.
A Dataset is a named collection of Entities that have the same properties.
A Dataset can be linked to Forms as Attachments. This will make it available to clients as an automatically-updating CSV.
Related APIs:
Listing Datasets¶
GET /v1/projects/{projectId}/datasets
The Dataset listing endpoint returns all published Datasets in a Project. If a Draft Form defines a new Dataset, that Dataset will not be included in this list until the Form is published.
The query ?deleted=true can be added to list deleted Datasets with their numeric IDs, which can be used to download a deleted Dataset's Entity data.
Request
Parameters
|
The numeric ID of the Project Example: |
(query) |
If set to Example: |
Response
HTTP Status: 200
Content Type: application/json
[
{
"name": "people",
"createdAt": "2018-01-19T23:58:03.395Z",
"projectId": 1,
"approvalRequired": true,
"ownerOnly": false
}
]
array
|
HTTP Status: 200
Content Type: application/json; extended
[
{
"name": "people",
"createdAt": "2018-01-19T23:58:03.395Z",
"projectId": 1,
"approvalRequired": true,
"ownerOnly": false,
"lastEntity": "2018-04-18T03:04:51.695Z",
"entities": 10,
"conflicts": 2
}
]
array
|
Creating Datasets¶
POST /v1/projects/{projectId}/datasets
You can create a Dataset with a specific name within a Project. This Dataset can then be populated with Entities via the API or via Forms and Submissions, and then used by other Forms. This endpoint allows a Dataset to be created programatically without an input form.
The name of a Dataset is case-sensitive in that it will keep the capitalization provided (e.g. "Trees"). But Central will not allow a second Dataset with the same name but different capitalization to be created (e.g. "trees" when "Trees" already exists).
By default, the Dataset will have no properties, but each Entity will have a label and a unique ID (uuid). You can add additional properties with this related endpoint.
The Dataset name must follow the the same rules as XML identifiers and not start with . or __. See the Entities XForms Specification for more information.
Request
Parameters
|
The numeric ID of the Project Example: |
Request body
{
"name": "Trees",
"approvalRequired": false
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"name": "people",
"createdAt": "2018-01-19T23:58:03.395Z",
"projectId": 1,
"approvalRequired": false,
"ownerOnly": false,
"lastUpdate": "2018-01-19T23:58:03.395Z",
"sourceForms": [],
"linkedForms": [],
"properties": []
}
object
|
HTTP Status: 409
Content Type: application/json
{
"code": 409.3,
"message": "A resource already exists with name,projectId value(s) of trees,1."
}
object
|
Dataset Metadata¶
GET /v1/projects/{projectId}/datasets/{name}
Returns the metadata of a published Dataset including properties and forms that create and consume the Dataset.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"name": "people",
"createdAt": "2018-01-19T23:58:03.395Z",
"projectId": 1,
"approvalRequired": true,
"ownerOnly": false,
"lastUpdate": "2020-10-10T03:04:51.695Z",
"sourceForms": [
{
"xmlFormId": "treeRegistration",
"name": "Tree Registration"
}
],
"linkedForms": [
{
"xmlFormId": "simple",
"name": "Simple"
}
],
"properties": [
{
"name": "the.age",
"odataName": "the_age",
"publishedAt": "2018-01-21T00:04:11.153Z",
"forms": [
{
"xmlFormId": "simple",
"name": "Simple"
}
]
}
]
}
object
|
Update Dataset Metadata¶
PATCH /v1/projects/{projectId}/datasets/{name}
You can use this endpoint to update approvalRequired and ownerOnly. However, you cannot update other properties, such as name.
The approvalRequired flag controls the Entity creation flow. If it is true, then the Submission must be approved before an Entity can be created from it. If it is false, then an Entity is created as soon as the Submission is received by ODK Central. By default, approvalRequired is false for Datasets created after v2023.3. Datasets created prior to that will have approvalRequired set to true.
The ownerOnly flag determines which Entities in the Dataset are included for download to an OpenRosa client. More specifically, it determines which Entities are included in a Form Attachment that has been linked to the Dataset. If ownerOnly is true, and the Actor using the OpenRosa client only has access to the Dataset CSV file via linked Form Attachments, then only Entities created by the Actor will be included. This is true of App Users, Web Users with a role of Data Collector, and Public Access Links. If ownerOnly is false, or if the Actor has direct access to the Dataset CSV file, then all Entities will be included. Accessing the Dataset CSV file via linked Form Attachments using a draftToken will also retrieve all Entities, this functionality assumes the draftToken is used by Actors with full dataset access, such as Project Managers and System Administrators. By default, ownerOnly is false.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
Request body
{
"approvalRequired": true
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"name": "people",
"createdAt": "2018-01-19T23:58:03.395Z",
"projectId": 1,
"approvalRequired": true,
"ownerOnly": false,
"lastUpdate": "2020-10-10T03:04:51.695Z",
"sourceForms": [
{
"xmlFormId": "treeRegistration",
"name": "Tree Registration"
}
],
"linkedForms": [
{
"xmlFormId": "simple",
"name": "Simple"
}
],
"properties": [
{
"name": "the.age",
"odataName": "the_age",
"publishedAt": "2018-01-21T00:04:11.153Z",
"forms": [
{
"xmlFormId": "simple",
"name": "Simple"
}
]
}
]
}
object
|
Deleting a Dataset¶
DELETE /v1/projects/{projectId}/datasets/{name}
(introduced: version 2026.1)
When a Dataset is deleted, it is soft-deleted and placed in the trash. After 30 days in the trash, the Dataset and all of its Entities will be automatically purged. Unlike Forms, deleted Datasets cannot be restored.
While in the trash, the Dataset's Entity data can still be exported as a CSV snapshot using GET /projects/:id/trash/datasets/:datasetId/entities.csv.
A Dataset cannot be deleted if any Forms are still linked to it, either as a source (a Form that creates/updates Entities in it) or as a consumer (a Form that uses it as an attachment). All such Forms must be updated first:
- To update a Form that writes to a Dataset, remove that dataset from the
entitiestab of the XLSForm and remove associatedsave_tos. - To update a Form that reads from a Dataset, replace the attachment with a static CSV or update the Form to not use that attachment.
A Form can also be deleted as a way to unlink it from a Dataset, but then that Form cannot be restored.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
HTTP Status: 409
Content Type: application/json
{
"code": "409.21",
"message": "You can't delete this dataset because there are Form(s) dependent on it."
}
object
|
Adding Properties¶
POST /v1/projects/{projectId}/datasets/{name}/properties
Creates a new Property with a specified name in the Dataset.
The name of a Property is case-sensitive in that it will keep the capitalization provided (e.g. "Firstname"). But Central will not allow another Property with the same name but different capitalization to be created (e.g. "FIRSTNAME" when "Firstname" already exists).
Property names follow the same rules as form field names (valid XML identifiers) and cannot use the reserved names of name or label, or begin with the reserved prefix __.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
Request body
{
"name": "circumference"
}
object
|
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
Deleting a Property¶
DELETE /v1/projects/{projectId}/datasets/{name}/properties/{propertyName}
(introduced: version 2026.1)
Deletes a published Property from a Dataset. The deletion is permanent, but a new property with the same name can easily be re-added.
A Property cannot be deleted if either of the following is true:
- Any published or draft Forms are currently writing to it (i.e. they have a
save_tomapping to this Property). Those Forms must be updated or deleted first. - Any Entities have a non-empty value for it. Those Entity values must be cleared first by updating each Entity to have an empty string for that Property.
If deletion is blocked, the 409 response includes a details.prerequisites object describing what needs to be resolved. For blocked Forms, it includes a list of the dependent Form IDs and names. For blocked Entities, it includes a totalCount and up to 3 example Entity UUIDs and labels.
A Form that reads a Dataset Property via an attachment may break after deleting the Property, so check any Forms that consume this Dataset as well.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
|
The name of the Property to delete Example: |
Response
HTTP Status: 200
Content Type: application/json
{
"success": true
}
object
|
HTTP Status: 409
Content Type: application/json
{
"code": "409.22",
"message": "Prerequisites for deleting the property \"age\" are not met.",
"details": {
"prerequisites": {
"dependentForms": {
"message": "You can't delete this property because there are Form(s) writing to it",
"details": {
"forms": [
{
"formName": "Registration Form",
"xmlFormId": "registration"
}
]
}
},
"nonEmptyEntities": {
"message": "You can't delete this property because there are Entity(ies) with the non-empty value for the 'age'",
"details": {
"totalCount": 42,
"entities": [
{
"uuid": "54a405a0-53ce-4748-9788-d23a30cc3afa",
"label": "John Doe"
},
{
"uuid": "9a2a3b4c-1234-4567-89ab-cdef01234567",
"label": "Jane Smith"
},
{
"uuid": "1b3d5f7a-9876-4321-abcd-ef0123456789",
"label": "Bob Jones"
}
]
}
}
}
}
}
object
|
Download Dataset¶
GET /v1/projects/{projectId}/datasets/{name}/entities.csv
Datasets (collections of Entities) can be used as Attachments in other Forms, but they can also be downloaded directly as a CSV file.
The CSV format closely matches the OData Dataset Service format, with columns for system properties such as __id (the Entity UUID), __createdAt, __creatorName, etc., the Entity Label label, and the Dataset/Entity Properties themselves. If any Property for an given Entity is blank (e.g. it was not captured by that Form or was left blank), that field of the CSV is blank.
The $filter querystring parameter can be used to filter on system-level properties, similar to how filtering in the OData Dataset Service works.
The $search querystring parameter can be used to search entity data (user-defined properties) and the label field, using the same search behavior as the OData Dataset Service.
This endpoint supports ETag header, which can be used to avoid downloading the same content more than once. When an API consumer calls this endpoint, the endpoint returns a value in the ETag header. If you pass that value in the If-None-Match header of a subsequent request, then if the Dataset has not been changed since the previous request, you will receive 304 Not Modified response; otherwise you'll get the new data.
Request
Parameters
|
The numeric ID of the Project Example: |
|
Name of the Dataset Example: |
(query) |
If provided, will filter responses to those matching the query. Only system-level Entity fields are available to reference. The operators Example: |
(query) |
If provided, will search entity data (user-defined properties) and the Example: |
Response
HTTP Status: 200
Content Type: text/csv
__id,label,geometry,species,circumference_cm,__createdAt,__creatorId,__creatorName,__updates,__updatedAt,__version
2c1ee90b-dde8-434b-9985-2eefd8465339,666cm purpleheart,-29.281608 -67.624883 0 0,purpleheart,667,2023-05-31T19:49:28.902Z,22,Alice,1,2023-05-31T19:52:34.467Z,1
84ac3a03-9980-4098-93a5-b81fdc6ea749,555cm wallaba,18.921876 77.309451 0 0,wallaba,555,2023-05-31T19:49:20.152Z,22,Alice,0,,1
string |
Downloading Deleted Dataset Entities¶
GET /v1/projects/{projectId}/trash/datasets/{datasetId}/entities.csv
(introduced: version 2026.1)
Returns a CSV snapshot of the Entities belonging to a soft-deleted Dataset. This is useful for exporting Entity data before the Dataset is permanently purged after 30 days in the trash.
The CSV format is identical to Download Dataset, except the filename will have a -deleted suffix (e.g. people-deleted.csv).
This endpoint uses the numeric Dataset ID rather than the Dataset name because the name alone is not sufficient to unambiguously identify a deleted Dataset (the same name could be reused). The numeric ID can be retrieved by listing Datasets with ?deleted=true.
Unlike Download Dataset, this endpoint does not support $filter, $search, or ETag.
Request
Parameters
|
The numeric ID of the Project Example: |
|
The numeric ID of the deleted Dataset (returned by listing Datasets with Example: |
Response
HTTP Status: 200
Content Type: text/csv
__id,label,geometry,species,circumference_cm,__createdAt,__creatorId,__creatorName,__updates,__updatedAt,__version
2c1ee90b-dde8-434b-9985-2eefd8465339,666cm purpleheart,-29.281608 -67.624883 0 0,purpleheart,667,2023-05-31T19:49:28.902Z,22,Alice,1,2023-05-31T19:52:34.467Z,1
string |