## TL;DR
Paging past the end happens when the agent trusts a page count or a next link that the API keeps serving, or when offset paging over changing data re-reads rows. The defence is layered: stop on an empty or short page, respect the API's own end signal, and deduplicate the pulled set on the seat's stable id before anything downstream counts it.

```text
when agent attempted to pull seat-count data, the export API paged past the end and returned duplicates: sync failed
```

## Use this when
- Seat counts come out higher than the billing system shows
- The same seat records appear multiple times in one pull
- Sync totals vary run to run for unchanged data

## Not for this skill when
- Customers genuinely hold duplicate seats across workspaces
- The API's total is wrong at the vendor and needs their fix

## Steps
1. Log per-page row counts and the first and last seat id of each page for one pull. Verify: the page where repetition begins is visible
2. Compare the API's stated total (if any) with the pulled unique count. Verify: the inflation size is quantified
3. Fix the loop's end condition to the API's documented end signal plus an empty-page stop. Verify: a test pull terminates at the true end
4. Deduplicate on stable seat id before counting, and report the duplicate count per run. Verify: downstream counts use unique seats even if a future paging bug recurs
5. Reconcile the corrected seat count against billing and flag accounts still diverging. Verify: seat truth now agrees across systems or carries named exceptions

## Variant phrasings
### export API pages past end duplicates
A related phrasing for the same underlying problem.
### seat count inflated by duplicate pages
A related phrasing for the same underlying problem.
### pagination duplicates in sync
A related phrasing for the same underlying problem.

Compatibility: Compatibility: seat and user export APIs from product admin or billing systems consumed by sync jobs, current versions.

## Why it happens
Counting is only as honest as the pull beneath it. End-condition bugs inflate quietly because duplicates look like growth. Per-page logging convicts the loop, and dedupe-on-id is the seatbelt that keeps any recurrence from reaching a renewal conversation.

## Edge cases / pitfalls
- Offset paging over live data duplicates and skips simultaneously; cursor paging avoids both where offered.
- Dedupe must never merge seats that share an email but are legitimately licensed in two workspaces. The stable id, not the email, is the key.
- A duplicate count that suddenly rises is itself a useful alert on API behaviour changes. Trend it.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_NlP5WuD9JiV6tTSqpkbqLg
