- Home
- Skills
- APIs & Backend
- API Pagination and Cursor Contract Design
API Pagination and Cursor Contract Design
Designs API collection pagination contracts: cursor tokens, keyset tie-breaking, page size caps, and stable traversal.
$5
Works with the AI tools you already use
API Pagination and Cursor Contract Design
Example session with this skill installed
Design the API pagination contract for our Enterprise Security Audit Log Collection endpoint.
- Subject: audit-service v3.0 (run-id: audit-logs-page-001) exposing GET /v1/audit-events over a 350-million-row append-only PostgreSQL ledger.
- Deciders: Lead API Standards Architect (Sarah Chen) and Database Guild Lead (Elena Rostova).
- Workload & Scale: Peak 1,200 search & export queries/sec; p95 latency budget <= 95 ms; ingestion rate 1,500 new audit events/sec.
- Tension: Compliance team requested traditional offset pagination (?page=1000&limit=50) to display total page numbers in their desktop UI; Elena Rostova warns that offset pagination at page 1,000 forces PostgreSQL to scan 50,000 rows (O(N) index traversal), causing severe database memory bloat and duplicate/skipped items when new events append (incident INC-2912 where deep offset queries crashed reader replicas), mandating opaque base64 cursor tokens (cursor=eyJ...), composite keyset tie-breaking on (created_at, event_id), max limit 100 items (default 25), and total item count omission on deep queries.
Write the pagination architecture contract under docs/.
- Read your context and instructions
- Compiled the api pagination
- Generated the UI component
Wrote docs/architecture/tasks/audit-logs-page-001/pagination-design/pagination-contract.md. Complete API pagination contract specifying opaque base64 cursor tokens, deterministic (created_at, event_id) keyset tie-breaking, max limit 100 bounds, and drift-free concurrent traversal.
---
skill: pagination-design
---
# API Pagination Contract: Security Audit Event Collection [PAGE-AUD-001]
## Summary
This specification establishes the API pagination contract for `audit-service v3.0` under run ID `audit-logs-page-001`, governing high-throughput querying across 350 million security audit events on `GET /v1/audit-events`. It resolves the conflict between frontend UI page navigation and database stability by decisively rejecting numeric offset pagination (`?page=N`). Following incident INC-2912 (where deep offset queries at page 1,000+ triggered reader replica memory exhaustion and skipped audit records during high-velocity 1,500 event/sec ingestion), the contract mandates opaque base64 cursor tokens encoding `(created_at, event_id)` keyset tuples, constant-time $O(1)$ index seek performance, a hard page size ceiling of 100 items (default 25), and total count suppression to prevent expensive `COUNT(*)` database locking.
## Detailed Description
Offset pagination (`OFFSET N LIMIT M`) degrades exponentially as page depth increases. In high-volume append-only event streams, new insertions shift row offsets dynamically, causing clients paging through records to observe duplicate events or skip entries entirely.
Incoming Client Query: GET /v1/audit-events?limit=25&cursor=eyJjcmVhdGVkX2F0IjoxNz...
│
▼
[ Gateway Cursor Decoder & Validator ]
├── 1. Base64 Decode & JSON Schema Validation
├── 2. Extract Keyset Tuple: (last_created_at, last_event_id)
└── 3. Enforce Limit Bounds (Default: 25, Ceiling: 100)
│
▼
[ Keyset Database Query (B-Tree Seek: O(1)) ]
WHERE (created_at, event_id) < ($1, $2) ORDER BY created_at DESC, event_id DESC LIMIT 26
│
▼
[ Response Generator: 25 Items + next_cursor (Latency p95 <= 60 ms) ]
### Criteria and weights
| Criterion | Why it matters here | Weight | Source of the weight |
|---|---|---|---|
| Constant-Time Seek Performance ($O(1)$) | Deep-page offset scans across 350M rows crash database memory pools (INC-2912). | 0.40 | Elena Rostova (Database Guild) |
| Concurrent Append Drift Stability | Ingesting 1,500 new events/sec must never cause paginated clients to miss audit records. | 0.30 | Compliance & Legal Audit Mandate |
| Latency SLA Headroom (p95 <= 95 ms) | Security SIEM export queries must stream continuous pages without latency spikes. | 0.15 | Intake SLA requirement |
| Opaque Cursor Decoupling | Encapsulate database indexing details inside opaque tokens, preventing client URL scraping. | 0.15 | Sarah Chen (API Standards) |
### Comparison
| Pagination Candidate | Deep-Page Execution Time | Append Drift Tolerance | Total Count Overhead | Evaluation |
|---|---|---|---|---|
| Option A: Offset / Limit (`page=1000`) | Degrades linearly ($O(N)$, > 8,500 ms) | Skips/duplicates rows on append | Expensive `SELECT COUNT(*)` scan | Rejected: Recreates INC-2912 database crash; leaks audit records. |
| Option B: Simple Timestamp Cursor | Constant time ($O(1)$ seek) | Fails on timestamp collisions | Omitted | Rejected: Identical millisecond timestamps drop co-occurring events. |
| Option C: Keyset Tuple + Opaque Cursor (Chosen) | Constant time ($O(1)$ seek, < 45 ms) | Zero drift (immutable tie-breaking) | Omitted; uses `has_more` boolean | Selected: Rock-solid stability, zero row skipping, constant latency. |
### Result
Option C is selected. Pagination is driven by opaque keyset tokens binding `created_at` and unique `event_id`.
---
### Required Mechanisms
#### 1. Task Contract & Pagination Parameters [MC-TC-01]
##### Request Parameters
- `limit` (integer, optional): Number of items requested. Default: `25`, Minimum: `1`, Maximum: `100`.
- `cursor` (string, optional): Base64-encoded URL-safe JSON string representing the keyset pointer. If omitted, returns the first page.
##### Response Envelope Contract
```json
```json
{
"items": [
{
"event_id": "evt_01h8x9a2b",
"action": "USER_ROLE_ELEVATED",
"actor_id": "usr_9921",
"created_at": "2026-09-16T14:22:10.104Z"
}
],
"pagination": {
"next_cursor": "eyJjcmVhdGVkX2F0IjoxNzI2NTA2MTMwMTA0LCJldmVudF9pZCI6ImV2dF8wMWg4eDlhMmIifQ==",
"has_more": true
}
}
#### 2. Cursor Encoding & Keyset Tie-Breaking [MC-CK-01]
- **Unencoded Keyset Payload**:
```json
{
"created_at": 1726506130104,
"event_id": "evt_01h8x9a2b"
}
- Serialization: UTF-8 bytes $\to$ Base64URL encoding without trailing padding (
=). - Database Seek Query Execution:
The backend fetches $N + 1$ records (limit + 1) to determinehas_morewithout issuing a secondary count query:SELECT event_id, action, actor_id, created_at FROM audit_events WHERE (created_at, event_id) < ($1, $2) ORDER BY created_at DESC, event_id DESC LIMIT 26; - Compound Index Alignment: Direct seek against composite index
idx_audit_events_created_id (created_at DESC, event_id DESC).
3. Concurrent Mutation & Drift Stability [MC-CM-01]
- Because records are strictly ordered by
(created_at, event_id), newly appended records with timestamps $> \text{cursor.created_at}$ appear exclusively on the first page. - Clients traversing historical pages observe a mathematically stable view: zero records are skipped and zero records are duplicated regardless of ingestion volume.
4. Error Taxonomy & Problem Details [MC-ET-01]
Malformed cursor tokens return RFC 9457 application/problem+json:
{
"type": "https://api.bank.com/errors/invalid-pagination-cursor",
"title": "Invalid Pagination Cursor",
"status": 400,
"detail": "The provided cursor token cannot be decoded or contains invalid keyset coordinates.",
"instance": "/v1/audit-events?cursor=malformed_string",
"code": "ERR_PAGINATION_CURSOR_INVALID"
}
Invariants and Contracts
Prohibition of Numeric Offset Pagination [INV-PAGE-01]
The collection endpoint must not accept `page` or `offset` parameters. Requests supplying
these query parameters must be rejected immediately with HTTP 400 Bad Request.
Deterministic Keyset Tie-Breaking [INV-PAGE-02]
Every cursor seek query must include the primary key `event_id` in the `WHERE` and `ORDER BY`
clauses to ensure deterministic row ordering during millisecond timestamp collisions.
Hard Limit Ceiling Invariant [INV-PAGE-03]
The `limit` parameter must strictly enforce a maximum ceiling of 100 items. Requests specifying
`limit > 100` must be rejected with HTTP 400 with `code: ERR_PAGE_SIZE_EXCEEDED`.
Total Count Suppression [INV-PAGE-04]
Responses must never return `total_count` or `total_pages`. Pagination state is expressed
exclusively via `has_more: boolean` and `next_cursor`.
Explicit Unknowns
- Performance impact of bi-directional cursor pagination (
previous_cursor) if SIEM compliance exports demand reverse scrolling (G-1). - Compression benefits of Protobuf-encoded binary cursors vs Base64 JSON under 1,200 req/sec network egress (G-2).
Traceability
| Claim | Classification | Source | Freshness |
|---|---|---|---|
| 350 million audit events volume | provided | Database scale intake | Current |
| 1,200 search QPS, 1,500 ingestion events/sec | provided | Traffic intake | Current |
| Latency budget p95 <= 95 ms | provided | SLA constraint | Current |
| Incident INC-2912 offset crash | provided | Post-mortem evidence | Historical |
| Opaque keyset cursor selection | decided | Sarah Chen & Elena Rostova | 2026-09-15 |
| Max limit 100, default 25 items | decided | API Standards Policy | 2026-09-15 |
Verification
No validator was supplied, so no command was run.
Reviewer self-check against pagination architecture contracts:
- Seek Determinism: PASS. Keyset seek
(created_at, event_id)operates in constant $O(1)$ index time. - Append Stability: PASS. Ingestion of 1,500 events/sec does not shift historical cursor offsets.
- Envelope Compliance: PASS. Response returns
items,next_cursor, andhas_more; suppressestotal_count. - Validation Guard: PASS. Malformed cursors and limits > 100 return RFC 9457 HTTP 400 problem details.
Open Decisions
DEC-PAGE-01: Elena Rostova to determine whether cursor expiry tokens should be introduced (e.g. invalidating cursors older than 7 days) to purge stale client leases (Owner: Elena Rostova).
Next steps
- Database platform team verifies index
idx_audit_events_created_idis deployed across all PostgreSQL partitions. - Platform developers deploy Base64 cursor serialization middleware in
services/audit/middleware/cursor_encoder.py. - Conduct staging performance test validating sub-50ms seek latency on queries starting at row 300,000,000.
api-pagination-and-cursor-contract-desig.tsx
TSX · React component
Example file from a real run - the skill writes it into your workspace.
Connects securely to your tools. The creator never sees your data.
What you get
About this skill
What it does
This skill maps authoritative collection identity, ordering, mutation/consistency and consumer-navigation requirements into an API pagination contract.
Use it when
Use when an accepted collection operation needs bounded, consumer-visible window/traversal semantics based on supplied collection, order, consistency and navigation contracts.
For example: “Our export tool pages through transactions with offset. It takes six hours, misses some rows, and duplicates others. The last page times out.”
What you get
- Pagination Standard Spec
Written as Markdown to <your output folder>/architecture/tasks/<run-id>/pagination-design/.
What it will not do
Do not use for resource/filter/sort/search/projection design, database queries/indexes, GraphQL schema, UI infinite scroll, exports, implementation, tuning or generic API design.
How it works
- Check every list endpoint is covered.
- Choose cursor or offset from the access pattern, not from convention.
- Make the ordering total and stable.
- Make the cursor opaque and encode what it needs.
- Bound page size and define the defaults.
- Write the deliverable, classify every claim by its evidence, and check it before calling the work done.
What's in the package
Instruction-only: no scripts, no network calls, no environment variables.
- LICENSE.txt
- SKILL.md
- agents/openai.yaml
- assets/output-template-task.md
- references/domain-rules.md
- references/operating-rules.md
- references/output-contract.md
How to install
Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.
- 1
Download the ZIP
Free skills download straight away. Paid skills unlock right after purchase.
- 2
Unzip into your skills folder
Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.
- 3
Ask your agent to use it
Restart the agent if it was already running. It picks the skill up automatically - no config needed.
Skills folder by agent
Click the path to copy it. Create the folder if it does not exist yet.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
30-day refund
Not a fit? Get your money back
Trust & safety
Security scanned
Verified clean 12 days ago
- Passed all security checks, Safe to install