---
title: "Data Document"
method: GET
path: "/v1/projects/{projectId}/forms/{xmlFormId}.svc/{table}"
tags: ["OData Form Service"]
---

# Data Document

`GET /v1/projects/{projectId}/forms/{xmlFormId}.svc/{table}`

The data documents are JSON representations of each table of `Submission` data. They follow the [corresponding specification](http://docs.oasis-open.org/odata/odata-json-format/v4.01/odata-json-format-v4.01.html), but apart from the representation of geospatial data as GeoJSON rather than the ODK proprietary format, the output here should not be surprising. If you are looking for JSON output of Submission data, this is the best place to look.

The `$top` and `$skip` querystring parameters, specified by OData, apply `limit` and `offset` operations to the data, respectively. The `$count` parameter, also an OData standard, will annotate the response data with the total row count, regardless of the scoping requested by `$top` and `$skip`. If `$top` parameter is provided in the request then the response will include `@odata.nextLink` that you can use as is to fetch the next set of data. As of ODK Central v2023.4, `@odata.nextLink` contains a `$skiptoken` (an opaque cursor), which allows you to page through Submissions with a consistent offset, even while new Submissions are being created.

While paging is possible through these parameters, it will not greatly improve the performance of exporting data. ODK Central prefers to bulk-export all of its data at once if possible.

As of ODK Central v1.1, the [`$filter` querystring parameter](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#_Toc31358948) is partially supported. In OData, you can use `$filter` to filter by certain data fields in the schema. The operators `lt`, `le`, `eq`, `ne`, `ge`, `gt`, `not`, `and`, and `or` are supported. The built-in functions `now`, `year`, `month`, `day`, `hour`, `minute`, `second` are supported. These supported elements may be combined in any way, but all other `$filter` features will cause an error.

The fields you can query against are as follows:

| Submission Metadata                      | REST API Name | OData Field Name          |
| ---------------------------------------- | ------------- | ------------------------- |
| Submission ID                            | `instanceId`  | `__id`                    |
| Submitter Actor ID                       | `submitterId` | `__system/submitterId`    |
| Submission Timestamp                     | `createdAt`   | `__system/submissionDate` |
| Submission Update Timestamp              | `updatedAt`   | `__system/updatedAt`      |
| Review State                             | `reviewState` | `__system/reviewState`    |
| Submission Delete Timestamp (v2024.3)    | `deletedAt`   | `__system/deletedAt`      |

You can use `$root` expression to filter subtables (repeats) by Submission Metadata, you'll have to prefix above fields by `$root/Submissions/` in the filter criteria. For example, to filter a repeat table by Submission Timestamp you can pass `$filter=$root/Submissions/__system/submissionDate ge 2020-02-01T00:00:00.000Z` in the query parameter.

Note that the `submissionDate` has a time component. This means that any comparisons you make need to account for the full time of the submission. It might seem like `$filter=__system/submissionDate le 2020-01-31` would return all results on or before 31 Jan 2020, but in fact only submissions made before midnight of that day would be accepted. To include all of the month of January, you need to filter by either `$filter=__system/submissionDate lt 2020-02-01T00:00:00.000Z` or `$filter=__system/submissionDate lt 2020-02-01`. Remember also that you can [query by a specific timezone](https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC).

Please see the [OData documentation](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#_Toc31358948) on `$filter` [operations](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part1-protocol/odata-v4.01-cs01-part1-protocol.html#sec_BuiltinFilterOperations) and [functions](http://docs.oasis-open.org/odata/odata/v4.01/cs01/part1-protocol/odata-v4.01-cs01-part1-protocol.html#sec_BuiltinQueryFunctions) for more information.

As of ODK Central v1.2, you can use `$expand=*` to expand all repeat repetitions. This is helpful if you'd rather get one nested JSON data payload of all hierarchical data, rather than retrieve each of repeat as a separate flat table with references.

The _nonstandard_ `$wkt` querystring parameter may be set to `true` to request that geospatial data is returned as a [Well-Known Text (WKT) string](https://en.wikipedia.org/wiki/Well-known_text) rather than a GeoJSON structure. This exists primarily to support Tableau, which cannot yet read GeoJSON, but you may find it useful as well depending on your mapping software. **Please note** that both GeoJSON and WKT follow a `(lon, lat, alt)` coördinate ordering rather than the ODK-proprietary `lat lon alt`. This is so that the values map neatly to `(x, y, z)`. GPS accuracy information is not a part of either standards specification, and so is presently omitted from OData output entirely. GeoJSON support may come in a future version.

As of ODK Central v2022.3, the [`$select` query parameter](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#_Toc31358942) is supported with some limitations:

+ `$select` and `$expand` can't be used together.

+ Child properties of repeats can't be requested using `$select`

As of ODK Central v2024.1, the [`$orderby` query parameter](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#_Toc31358952) is now supported, and can sort on the same fields as `$filter`, noted above. The order can be specified as `ASC` (ascending) or `DESC` (descending), which are case-insensitive. Multiple sort expressions can be used together, separated by commas, e.g. `$orderby=__system/submitterId ASC, __system/reviewState DESC`.

As the vast majority of clients only support the JSON OData format, that is the only format ODK Central offers.

## Path parameters

- `projectId` number, required
- `xmlFormId` string, required
- `table` string, required

## Query parameters

- `$skip` number
- `$top` number
- `$count` boolean
- `$wkt` boolean
- `$filter` string
- `$orderby` string
- `$expand` string
- `$select` string
- `$skiptoken` string

## Response `200`

OK

- object
  - `@odata.context` string
  - `value` object[]
    - `__id` string, required
    - `age` number, required
    - `meta` object, required
      - `instanceID` string
    - `name` string, required

## Other responses

- `406` — Not Acceptable
- `501` — Not Implemented

## Changes

- **2025-12-20** `022694254f0d` — 1 info
  - api operation id `Data Document` removed and replaced with `dataDocument`
- **2025-10-27** `b11b54eea487` — 1 info
  - removed the non-success response with the status `403`
- **2025-03-13** `e8c2858fd4eb` — 2 info
  - api operation id `dataDocument` removed and replaced with `Data Document`
  - added the non-success response with the status `403`

[Change history](https://skmtc.dev/getodk/apis/odk-central-api/changes/v1/projects/:projectId/forms/:xmlFormId.svc/:table/get.md)

---

[API](https://skmtc.dev/getodk/apis/odk-central-api.md) · [All operations](https://skmtc.dev/getodk/apis/odk-central-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/getodk/odk-central-api/revisions/d4f5ba77f644/schema)
