Debugging LinkedIn REST v2 Pagination: Truncated, Duplicated, or Missing Items
Why LinkedIn v2 list endpoints return fewer items than expected, and how to page through them correctly using start and count.
20 Dec 2025, 08:23 UTC

Symptom: truncated, duplicated, or missing items in list responses
You call a LinkedIn REST v2 list endpoint and receive fewer members, posts, or organizations than you expect. The next page repeats items from the previous page, skips some entirely, or stops before the end of the list. This usually means the client is treating LinkedIn's offset-based paging as cursor-based paging, or it is ignoring the paging metadata block that LinkedIn returns with every list response.
Useful takeaway: LinkedIn v2 list endpoints use offset pagination with start and count query parameters. The response paging block—{ count, start, total }—is the authoritative source of truth. A short final page is normal; it does not mean an error unless the request itself failed.
Cause and diagnostic table
| Cause | Symptom |
|---|---|
| count parameter omitted | Server applies a default, often 10, silently truncating the page |
| count above endpoint cap | Value is clamped to the maximum without an error |
| start misaligned or beyond total | Empty pages, overlapping items, or early termination |
| Missing x-restli-protocol-version: 2.0.0 header | Legacy response shape or v1 behavior |
| HTTP 429 mistaken for end of data | Client stops paging after a rate-limited request |
Check 1: confirm the request is using REST v2
LinkedIn distinguishes REST v2 from older versions with a required header. Without it, the response shape and paging behavior can change.
curl -i "https://api.linkedin.com/v2/{endpoint}" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "x-restli-protocol-version: 2.0.0"
- Where to run: any terminal or API client with network access to api.linkedin.com
- Permissions: an access token with the scopes required by the endpoint
- Placeholders: replace {endpoint} with the resource path and ACCESS_TOKEN with a valid token
- Expected check: HTTP 200 and the response header x-restli-protocol-version: 2.0.0
- Risk: omitting the header can produce legacy v1 behavior or unexpected errors
Check 2: read the paging block and the count actually applied
Inspect the JSON response body. Look for the paging block:
{
"elements": [ ... ],
"paging": {
"count": 25,
"start": 0,
"total": 100
}
}
count is the number of items the server actually returned on this page. start is the zero-based offset of the first item. total is the server's estimate of the full result set size. If you requested count=100 but paging.count is 25, the endpoint clamped your request to its maximum. Endpoint caps vary—commonly 100, sometimes 25 or lower—so confirm the cap per endpoint rather than hardcoding one value.
Check 3: verify start arithmetic and the stop condition
To request the next page, set start to the previous start plus the number of elements actually returned, not the number you requested:
next_start = previous_start + len(elements)
Stop paging when start >= paging.total, or when a page returns zero elements. Do not stop merely because a page returned fewer items than requested; that is expected on the final page. If paging.total is absent on an endpoint that normally exposes it, treat that as a possible platform issue.
Check 4: distinguish a final short page from a rate-limit failure
LinkedIn enforces per-application and per-member rate limits. A rate-limited request returns HTTP 429, often with Retry-After or rate-limit headers. If your client interprets a failed page as an empty final page, it will stop early and report missing data.
Before treating a short or empty page as the end of data:
- Confirm the HTTP status is 200.
- If you see 429 or 5xx, honor Retry-After with exponential backoff.
- Resume from the last successful start, not from zero.
- Never retry in a tight loop; that accelerates rate-limit exhaustion.
Fixes tied to findings
For missing or truncated output, set an explicit count at or below the endpoint cap, then loop start += returnedCount until start >= paging.total or a page returns zero elements.
For duplicated or skipped items, align start to multiples of count and stop when start + count > total. Base the next offset on the returned element count, not the requested count.
For legacy response shapes, add x-restli-protocol-version: 2.0.0 and call /v2/ paths only.
For rate-limit failures read as end-of-data, implement backoff and resume from the last successful offset.
Example pagination loop
The following pseudocode shows the pattern. It is not tested against LinkedIn's production API and should be adapted to your language and HTTP client:
start = 0
count = 50
all_items = []
while True:
response = GET /v2/{endpoint}?start={start}&count={count}
if response.status == 429:
wait(response.headers["Retry-After"] or backoff())
continue
if response.status != 200:
raise Error(response.status, response.body)
page = response.json()
elements = page["elements"]
all_items.extend(elements)
paging = page["paging"]
start = paging["start"] + len(elements)
if len(elements) == 0 or start >= paging["total"]:
break
Escalation criteria
Escalate to LinkedIn developer support, including the x-li-uuid request ID from the response headers, when:
- paging.total is missing on an endpoint that should expose it
- counts are clamped below the documented maximum
- 429 responses persist beyond documented rate-limit windows
- identical requests return different result sets, which can indicate replication lag
A 403 on a required scope is a permissions issue, not a pagination bug; do not escalate it as a paging defect.
Limitations and practical verification
Endpoint-specific defaults and caps change over time, and some endpoints omit paging.total. Member-data access is gated by approved scopes and products; a missing scope produces 403, not a pagination error.
Before relying on this logic in production:
- Call a v2 list endpoint you have access to with x-restli-protocol-version: 2.0.0 and inspect the paging block and response headers directly.
- Request a high count and observe the paging.count actually applied, comparing it with the endpoint's documented maximum.
- Page through a known dataset with start=0,count=N and assert there are no duplicates or gaps and that the final page returns fewer than N elements.
- Cross-check current limits, deprecations, and rate-limit status in LinkedIn's developer portal.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.