Pagination, Filtering & Sorting
Every list endpoint in the Oho REST API — /workers, /credentials, /applicants,
/screening-packages, /fetch-requests, and the rest — shares the same query parameters for
free-text search, paging, and ordering. The entity lists that carry a record-recency index
(/workers, /credentials, /applicants, /exemptions) add an updatedAfter / updatedBefore
window on top. Learn them once here and they behave the same wherever they appear.
Read API Basics first — it covers base URLs, the Authorization header, the
list response envelope, and soft deletes that this page builds on. The examples assume $OHO_BASE
and $OHO_TOKEN are set.
The shared parameters
These apply to every list endpoint:
| Parameter | Type | Default | Purpose |
|---|---|---|---|
query | string | * | Free-text search across the entity's indexed fields. |
page | integer | 1 | 1-based page number to return. |
pageSize | integer | 25 | Results per page. Clamped to the range 1–100. |
sort | string | — | Order results as field:asc or field:desc. |
includeDeleted | boolean | false | Include soft-deleted records in the results. |
Two more parameters — updatedAfter and updatedBefore — are available on the entity lists that
index a last-modified time (/workers, /credentials, /applicants, /exemptions); see
Filtering by update time below.
All of these are optional, and they compose: a single request can search, page, sort, and (where
supported) filter by update window at the same time. Endpoints layer their own entity-specific
filters on top — for example /credentials adds status and jurisdiction — but the parameters
above behave identically across every list.
Searching with query
query runs a free-text search over the entity's indexed fields. Omit it (or pass the default
*) to match everything:
curl -sS "$OHO_BASE/workers?query=jordan" \
-H "Authorization: Bearer $OHO_TOKEN"
To look a resource up by your own upstream identifier instead of searching, use the
entity-specific exact-match filters (such as externalId) documented on each endpoint rather
than query.
Paging through results
Results come back one page at a time. Use page to walk forward and pageSize to control how
many rows each page holds:
curl -sS "$OHO_BASE/workers?page=2&pageSize=50" \
-H "Authorization: Bearer $OHO_TOKEN"
The meta block echoes the paging state and the total, so you can tell when you've reached the
end:
{
"data": [{ "id": "wkr_V1StGXR8Z5jdHi6B", "type": "worker", "...": "..." }],
"meta": { "page": 2, "pageSize": 50, "total": 137, "requestId": "..." }
}
You've fetched the last page when page * pageSize >= total. With the values above, page 3
returns the final 37 records.
pageSize is clamped, not rejectedpageSize is clamped into the range 1–100. Requesting pageSize=500 does not error — the
server silently caps it at 100; values below 1 are raised to 1. Always read the pageSize
returned in meta rather than assuming the value you sent was honored. To pull a large set, page
through it instead of trying to raise the cap.
Sorting with sort
Pass a field name and a direction separated by a colon:
# Most recently updated workers first
curl -sS "$OHO_BASE/workers?sort=lastUpdated:desc" \
-H "Authorization: Bearer $OHO_TOKEN"
Direction is desc for descending; any other value — including an omitted or unrecognized
direction — is treated as ascending, so sort=lastUpdated and sort=lastUpdated:asc are
equivalent. The direction is not validated, so a typo silently sorts ascending rather than
returning an error.
Which fields are sortable depends on the entity — lastUpdated (the record's last-modified time)
is available on the lists that index it, and each endpoint documents the rest. Some endpoints
(such as /compliance-checks) enforce an allow-list and reject an unknown field with 400;
others pass the field through to the search layer. Check the per-endpoint
API Reference for the sortable fields and the default ordering, which varies
by entity (for example, workers default to display name ascending).
Filtering by update time
On /workers, /credentials, /applicants, and /exemptions, updatedAfter and
updatedBefore bound results by each record's last-modified time (the indexed lastUpdated
field). Each accepts either an ISO 8601 instant (2026-01-01T00:00:00Z) or a bare date
(2026-01-01, interpreted as UTC midnight); an unparseable value returns 400. The boundaries
are deliberately asymmetric:
updatedAfteris inclusive (>=) — a record updated exactly at the supplied instant is kept.updatedBeforeis exclusive (<) — a record updated exactly at the supplied instant is dropped.
This pairing makes it safe to page through changes in contiguous windows without seeing the
same record twice at a boundary. Combine both to select a half-open [from, to) range:
# Credentials changed during June 2026
curl -sS "$OHO_BASE/credentials?updatedAfter=2026-06-01T00:00:00Z&updatedBefore=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer $OHO_TOKEN"
A common sync pattern is to store the high-water mark from your last poll and pass it as
updatedAfter on the next one, ordering by sort=lastUpdated:asc so you process changes
oldest-first.
Including soft-deleted records
DELETE is a soft delete (see API Basics), and soft-deleted
records are hidden from lists by default. Pass includeDeleted=true to bring them back —
deleted rows carry deleted: true so you can tell them apart:
curl -sS "$OHO_BASE/credentials?includeDeleted=true" \
-H "Authorization: Bearer $OHO_TOKEN"
Putting it together
A single request can use every convention at once. The example below searches credentials, restricts to those changed since a given instant, sorts newest-first, and takes the first page of 50 — deleted records excluded:
curl -sS "$OHO_BASE/credentials?query=nurse&updatedAfter=2026-06-28T00:00:00Z&sort=lastUpdated:desc&page=1&pageSize=50" \
-H "Authorization: Bearer $OHO_TOKEN"
For the entity-specific filters that layer on top of these, see the per-endpoint API Reference.