Oracle Fusion REST API Pagination: limit, offset, hasMore, and totalResults
Every collection GET against an Oracle Fusion REST API is paginated whether you ask for it or not. If you call GET /workers and process the response as “all workers,” you silently got the first 25 rows — the default page size — and nothing tells you loudly that thousands more exist. Half the pagination bugs in Fusion integrations come from that one default; the other half come from mishandling offset. This guide covers the parameters, the canonical hasMore loop, what totalResults really costs, and the special case of paginating expanded child resources.
All examples use an anonymized pod (acme.fa.us2.oraclecloud.com) and placeholder data — swap in your own.
The pagination fields in every collection response
A collection GET returns a wrapper, not a bare array:
{
"items": [ ... ],
"count": 25,
"hasMore": true,
"limit": 25,
"offset": 0,
"links": [ ... ]
}
count— how many items are in this page (not the total).hasMore—trueif the server has more rows past this page. This is your loop condition.limit— the page size the server actually used (it can override what you asked for).offset— the index of the first item in this page, 0-based.totalResults— only present when you explicitly request it (see below).
limit and offset basics
limit sets the page size, offset sets the starting index:
# Rows 51–100 of the workers collection
curl -u '[email protected]:YourPassword' \
'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers?limit=50&offset=50&onlyData=true'
Three rules that prevent most surprises:
- Default limit is 25 when you don’t send one.
- The cap is 500 on most resources — ask for
limit=10000and the server quietly serves 500 (check thelimitfield in the response to see what you actually got). offsetis 0-based —offset=0starts at the first row,offset=50at the 51st. If your middleware assumes 1-based offsets (a real bug seen in identity-management connectors), every page after the first drops or duplicates one record.
onlyData=true strips the per-item links arrays and shrinks payloads dramatically — always use it when you’re iterating pages and don’t need HATEOAS links.
The canonical hasMore loop
Never precompute page counts from a total. Loop on hasMore:
BASE='https://acme.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/invoices'
LIMIT=500
OFFSET=0
while :; do
PAGE=$(curl -s -u '[email protected]:YourPassword' \
"$BASE?limit=$LIMIT&offset=$OFFSET&onlyData=true&orderBy=InvoiceId")
echo "$PAGE" | jq -r '.items[].InvoiceNumber'
[ "$(echo "$PAGE" | jq '.hasMore')" = "true" ] || break
OFFSET=$((OFFSET + LIMIT))
done
The same shape in pseudo-code for any client:
offset = 0
do:
page = GET resource?limit=500&offset=offset&onlyData=true&orderBy=<stable key>
process(page.items)
offset += page.limit # use the server's limit, not your requested one
while page.hasMore
Two details matter more than they look:
- Increment by
page.limit, not your requested limit. If the server overrides your page size, incrementing by the wrong number skips rows. - Always send
orderByon a stable, unique key (PersonId,InvoiceId). Offset pagination without a deterministic sort order can return duplicates or gaps when rows are inserted between page calls — this shows up as “random missing records” in nightly syncs and is close to impossible to reproduce in testing.
totalResults: useful, but not free
totalResults is off by default because it forces an extra count query on every page:
curl -u '[email protected]:YourPassword' \
'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers?totalResults=true&limit=1&onlyData=true'
{
"items": [ ... ],
"totalResults": 48213,
"count": 1,
"hasMore": true,
"limit": 1,
"offset": 0
}
Use it once up front — with limit=1 — when you genuinely need a total (progress bars, reconciliation counts), then run the actual export loop without it. Requesting totalResults=true on every page of a large extraction adds a count query per page for information you already learned on page one.
Pagination + q filters and finders
limit/offset compose with everything else on the URL. Filtered collections paginate exactly the same way:
# Page through all active workers, filtered server-side
curl -u '[email protected]:YourPassword' \
'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers?q=assignments.AssignmentStatusType=%27ACTIVE%27&limit=500&offset=0&onlyData=true&orderBy=PersonId'
Filter first, paginate second: a q filter that cuts 48,000 rows to 3,000 saves you 90 pages before pagination even starts. The same applies to finders.
Paginating expanded child resources
expand has its own pagination story. From REST framework version 3, an expanded child comes back as a collection wrapper (with its own items, count, hasMore) instead of a bare array — precisely so large children can paginate. And any child with more than 500 items isn’t expanded at all: Oracle returns the usual links entry instead of inlining the data.
So the robust pattern for parent + large child is:
- Page through the parent collection with the
hasMoreloop. - For each parent row where the child matters, follow the child URI and paginate it independently:
# Child collections take limit/offset like any other collection
curl -u '[email protected]:YourPassword' \
'https://acme.fa.us2.oraclecloud.com/hcmRestApi/resources/11.13.18.05/workers/00020000000EACED.../child/assignments?limit=100&offset=0&onlyData=true'
If you expand several children on a wide parent query “to save calls,” you usually pay more in payload size than you save in round trips. Expand small, bounded children (emails, phones); fetch large ones (assignments across history) through their own paginated URIs.
Common errors and gotchas
- First 25 rows only — no
limitsent, default applied,hasMoreignored. The classic. - Off-by-one on offset — a 1-based assumption in the client; symptom is one duplicated or missing record per page boundary.
- Silent limit override — you asked for 1,000, got 500, and incremented offset by 1,000: every second page is skipped. Increment by the response’s
limit. - Unstable ordering — no
orderBy, rows shifting between calls, nightly sync “loses” records nondeterministically. - 429 rate limits mid-loop — a 500-per-page loop over a big resource is thousands of calls; back off on 429 and resume from the saved
offsetrather than restarting. - hasMore=false but you expected more — check whether row-level security trimmed the collection; the API paginates only what your roles let you see.
Check page sizes before you build the loop
How many rows a resource returns — and which fields you can filter on to shrink them — is endpoint-specific. The workers endpoint alone exposes 307 queryable fields and 20 child resources; OPAL’s endpoint catalog shows q fields, finders, and child resources for the top HCM and FSCM endpoints offline, so you can design the filter before burning API calls. For full request walkthroughs around pagination — auth, expand, error handling — see the HCM examples post and the FSCM REST API guide.
This post is part of our complete Oracle Fusion API guide — auth, base URLs, q filters, finders, and key endpoints in one place.