Pagination
The Data Extraction API uses cursor-based pagination with
ContinuationToken. This approach is reliable for large datasets — you won’t
miss or duplicate records even if data changes between pages.
How it works
Section titled “How it works”- First request: call the endpoint with your filter parameters (date range, project, etc.)
- Check the response: if there’s more data, the response includes a
continuationToken - Next page: pass the token back as the
ContinuationTokenquery parameter (keep all other parameters the same) - Repeat until no
continuationTokenis returned
Response structure
Section titled “Response structure”Every Data Extraction endpoint returns this structure:
{ "data": [], "links": { "next": "/v1/time-registrations?FromDateTime=...&ContinuationToken=eyJ..." }, "continuationToken": "eyJ..."}| Field | Description |
|---|---|
data | Array of records for the current page |
links.next | URL for the next page (convenience — you can also build it yourself) |
continuationToken | Opaque token to pass as the ContinuationToken query parameter. Absent/empty when there are no more pages. |
Shared filter parameters
Section titled “Shared filter parameters”The extraction endpoints share a common filter model:
| Parameter | Type | Description |
|---|---|---|
FromDateTime | datetime | Full-sync window start |
ToDateTime | datetime | Full-sync window end |
ModifiedSince | datetime | Incremental sync: only records modified at/after this instant. Switches the ordering to modification time. |
ModifiedBefore | datetime | Upper bound for incremental sync. Requires ModifiedSince and must be after it. |
ProjectId | string | Restrict to one project |
CompanyId | string | Only data registered in (owned by) this company |
OwnCompanyDataOnly | bool | Only data owned by the requesting company, excluding data shared from external companies |
ExcludeDataFromSubsidiaries | bool | For parent companies: exclude subsidiary data |
ChunkLimit | int | Target page size. Default 2500, clamped to 1–10000. |
ContinuationToken | string | The paging cursor |
Metadata endpoints (project, user, resource) support the same model minus the
FromDateTime/ToDateTime window.
Full vs incremental sync
Section titled “Full vs incremental sync”| Mode | Trigger | Use for |
|---|---|---|
| Full | ModifiedSince not set | Initial backfill of a date window |
| Incremental | ModifiedSince set | Ongoing sync — catches new and edited records; several endpoints also emit deletion tombstones (isDeleted: true) in this mode |
The recommended pattern: one full sync to backfill, then scheduled
incremental syncs passing ModifiedSince = <last successful sync timestamp>.
Example: paginating through all records
Section titled “Example: paginating through all records”export DITIO_REPORTING_BASE="https://core-api.ditio.dev/reporting" # test
# Page 1curl -H "Authorization: Bearer $TOKEN" \ "$DITIO_REPORTING_BASE/v1/time-registrations?FromDateTime=2026-01-01&ToDateTime=2026-12-31"
# Page 2 (using the continuation token from page 1)curl -H "Authorization: Bearer $TOKEN" \ "$DITIO_REPORTING_BASE/v1/time-registrations?FromDateTime=2026-01-01&ToDateTime=2026-12-31&ContinuationToken=eyJwYWdl..."
# Continue until continuationToken is absentBest practices
Section titled “Best practices”- Don’t parse the token. The
ContinuationTokenis an opaque string; its format may change. - Don’t modify filter parameters between pages. Once you start paginating, keep the filter identical and only add the token — changing filters restarts the stream.
- Handle token expiry. If your access token expires mid-pagination,
refresh it and continue with the same
ContinuationToken. - Keep
ModifiedSincetight. For incremental syncs, pass a timestamp close to your last successful sync — a far-backModifiedSinceon a large tenant is the heaviest query pattern. - Chunk large backfills. Prefer month-by-month
FromDateTime/ToDateTimewindows over one unbounded call.
Related
Section titled “Related”- Quickstart — pagination in a working example
- Image Extraction — the multi-source variant of this pattern