If you are looking to unlock 40+ HRIS and ATS integrations with a single API key, check out Knit API. If not, keep reading
Note: This is a part of our series on API Pagination where we solve common developer queries in detail with common examples and code snippets. Please read the full guide here where we discuss page size, error handling, pagination stability, caching strategies and more.
Ensure that the pagination remains stable and consistent between requests. Newly added or deleted records should not affect the order or positioning of existing records during pagination. This ensures that users can navigate through the data without encountering unexpected changes.
5 ways for pagination stability
To ensure that API pagination remains stable and consistent between requests, follow these guidelines:
1. Use a stable sorting mechanism
If you're implementing sorting in your pagination, ensure that the sorting mechanism remains stable.
This means that when multiple records have the same value for the sorting field, their relative order should not change between requests.
For example, if you sort by the "date" field, make sure that records with the same date always appear in the same order.
2. Avoid changing data order
Avoid making any changes to the order or positioning of records during pagination, unless explicitly requested by the API consumer.
If new records are added or existing records are modified, they should not disrupt the pagination order or cause existing records to shift unexpectedly.
3. Use unique and immutable identifiers
It's good practice to use unique and immutable identifiers for the records being paginated. T
This ensures that even if the data changes, the identifiers remain constant, allowing consistent pagination. It can be a primary key or a unique identifier associated with each record.
4. Handle record deletions gracefully
If a record is deleted between paginated requests, it should not affect the pagination order or cause missing records.
Ensure that the deletion of a record does not leave a gap in the pagination sequence.
For example, if record X is deleted, subsequent requests should not suddenly skip to record Y without any explanation.
5. Use deterministic pagination techniques
Employ pagination techniques that offer deterministic results. Techniques like cursor-based pagination or keyset pagination, where the pagination is based on specific attributes like timestamps or unique identifiers, provide stability and consistency between requests.
Also Read: 5 caching strategies to improve API pagination performance
Frequently Asked Questions
What is pagination stability in APIs?
Pagination stability means a client paginating through a dataset gets consistent, complete results — no duplicates, no missing records — even if the underlying data is modified during the pagination session. Stable pagination is critical for integration sync use cases where completeness matters. Unstable pagination — most commonly caused by offset on mutable data — is one of the most frequent but hardest-to-debug data integrity issues in API integrations. Knit builds pagination stability into its sync engine using cursor-based and keyset pagination with checkpointing, so concurrent writes to platforms like Workday, BambooHR, or SAP SuccessFactors don't corrupt in-progress data fetches.
Why does offset pagination produce inconsistent results?
Offset pagination produces inconsistent results because it defines page boundaries by row position (skip N, return M) rather than by a stable record pointer. If a record is inserted into the dataset after page 1 is fetched, every record shifts forward by one — the record pushed from page 1 into page 2 territory gets skipped. Deletes cause the reverse: records shift backward and appear twice. Offset is only reliable for truly static datasets where no inserts, updates, or deletes occur between pagination requests. For any live dataset, cursor-based or keyset pagination is the correct approach.
How do you implement stable cursor-based pagination?
Stable cursor-based pagination requires three things: a stable sort field (an indexed column like id or created_at that doesn't change once set), a cursor that encodes the last-seen value of that field (typically base64-encoded to prevent client manipulation), and a query that filters strictly after that value rather than using OFFSET. The server returns the cursor for the last record in each page; the client passes it back as the after parameter on the next request. To handle concurrent inserts, sort by a monotonically increasing field — auto-increment id is the most reliable, or a combination of created_at and id for tie-breaking when timestamps collide.
What is keyset pagination and when should I use it?
Keyset pagination (also called seek pagination) filters results using the actual values of one or more indexed columns rather than a row count offset. Instead of "skip 10,000 rows", a keyset query says "return records where id > 10000 ORDER BY id LIMIT 100". This is dramatically faster on large tables because the database uses an index seek rather than a full scan. Use keyset pagination when your dataset has millions of records, you need consistent performance across all pages (not just early ones), or deep pagination is a common access pattern. The main limitation is that it doesn't support jumping to an arbitrary page by number — access is sequential.
How do you handle pagination when records are deleted mid-sync?
Deletes mid-sync are only a problem with offset pagination — cursor and keyset pagination are unaffected because they don't depend on row position. If you must use offset, mitigate deletes by: fetching in reverse order (newest first) so deletes push records toward earlier already-fetched pages; using soft-deletes where records are marked deleted but not removed, filtering them out after fetching; or using a change-data-capture approach where you consume a log of inserts, updates, and deletes rather than paginating the live table. For integration sync, delta-based fetching — pulling only records modified since the last sync, including delete events — avoids the full re-pagination problem entirely.
What is cursor drift and how do you prevent it?
Cursor drift occurs when the sort field used for cursor pagination is not truly stable — for example, using updated_at as the cursor field when records can be re-updated between page requests. If a record from page 1 gets its updated_at timestamp bumped while you're fetching page 3, it will reappear in a later page (paginating by ascending updated_at) or be skipped (if descending). Prevent cursor drift by paginating on immutable fields: auto-increment id is the most reliable, or a combination of created_at and id for tie-breaking. If you need both creation-order and modification-order access, expose separate cursor-paginated endpoints for each rather than trying to serve both with one cursor.



.webp)

