rest-api-pagination-patterns
REST API pagination for inbound and outbound integrations: Salesforce QueryMore, cursor-based, offset-based, Link header, page-size tuning, rate limit interaction. NOT for Bulk API (use bulk-api-patterns). NOT for GraphQL connection pagination (use graphql-api-patterns).
Best use case
rest-api-pagination-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
REST API pagination for inbound and outbound integrations: Salesforce QueryMore, cursor-based, offset-based, Link header, page-size tuning, rate limit interaction. NOT for Bulk API (use bulk-api-patterns). NOT for GraphQL connection pagination (use graphql-api-patterns).
Teams using rest-api-pagination-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/rest-api-pagination-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How rest-api-pagination-patterns Compares
| Feature / Agent | rest-api-pagination-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
REST API pagination for inbound and outbound integrations: Salesforce QueryMore, cursor-based, offset-based, Link header, page-size tuning, rate limit interaction. NOT for Bulk API (use bulk-api-patterns). NOT for GraphQL connection pagination (use graphql-api-patterns).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# REST API Pagination Patterns
Activate when integrating with a paginated REST API — either consuming an external API from Apex or serving a paginated endpoint from Salesforce. Pagination mistakes cause three classic failures: infinite loops, missed records, and duplicate records due to concurrent writes between page fetches.
## Before Starting
- **Identify pagination style.** Cursor / Next-link / Offset / Link-header / Token-based — all have different termination semantics.
- **Plan termination.** Every pagination loop needs a safety cap (max iterations) plus the documented termination signal.
- **Respect rate limits.** Back off on 429; implement exponential backoff.
## Core Concepts
### Salesforce QueryMore (outbound to external consumer)
```
/services/data/v60.0/query?q=SELECT+Id+FROM+Account
→ { "done": true, "nextRecordsUrl": "/services/data/v60.0/query/01g...", "records": [...] }
```
Loop: fetch `nextRecordsUrl` until `done == true`.
### Cursor-based (opaque token)
Response includes a cursor string; pass back as `?cursor=<value>` until the server returns an empty cursor or explicit end-of-stream flag.
### Offset / limit
Classic `?offset=0&limit=100`. Simple but vulnerable to drift: records inserted/deleted between pages cause missed or duplicate rows.
### Link header (RFC 5988)
```
Link: <https://api/x?page=2>; rel="next", <https://api/x?page=10>; rel="last"
```
Parse headers; loop until no `rel="next"` present.
### Rate limit headers
`X-RateLimit-Remaining`, `Retry-After` — consult before issuing the next page.
## Common Patterns
### Pattern: QueryMore loop in Apex
```
HttpResponse resp = http.send(req);
Map<String,Object> body = (Map<String,Object>) JSON.deserializeUntyped(resp.getBody());
List<Object> all = new List<Object>();
all.addAll((List<Object>) body.get('records'));
while (body.get('done') == false) {
String nextUrl = (String) body.get('nextRecordsUrl');
HttpRequest r2 = new HttpRequest();
r2.setEndpoint(base + nextUrl);
// auth ...
resp = http.send(r2);
body = (Map<String,Object>) JSON.deserializeUntyped(resp.getBody());
all.addAll((List<Object>) body.get('records'));
}
```
### Pattern: Cursor loop with safety cap
```
String cursor = null;
Integer safetyCap = 1000; // max pages
for (Integer i = 0; i < safetyCap; i++) {
// fetch with cursor
if (cursor == null || cursor == '') break;
}
if (i == safetyCap) throw new IntegrationException('Pagination safety cap hit');
```
### Pattern: Rate-limit-aware pagination
Check `X-RateLimit-Remaining`; if < threshold, sleep per `Retry-After` before next page. In Apex: use Queueable chaining for long-running paginations (cannot `Thread.sleep`).
## Decision Guidance
| Situation | Pagination style |
|---|---|
| Salesforce inbound data | QueryMore |
| Large stable dataset | Cursor |
| Small dataset, admin UI | Offset/limit |
| Complex filter with stable ordering | Cursor |
| Lots of concurrent writes | Cursor with created-since filter |
## Recommended Workflow
1. Identify the source API's pagination style from documentation.
2. Implement the loop with an explicit termination signal AND a safety cap.
3. For offset/limit: either confirm dataset is stable or add resume tokens.
4. Parse rate-limit headers; back off on 429.
5. For long paginations in Apex, chain Queueables — each handles one page batch.
6. Persist intermediate results in case of mid-stream failure.
7. Write integration test that mocks 3+ pages including empty-tail.
## Review Checklist
- [ ] Termination signal matches API spec
- [ ] Safety cap on page count (avoid infinite loops)
- [ ] Rate-limit headers honored
- [ ] Apex: long paginations chained via Queueable (callout limit: 100/transaction)
- [ ] Resume/checkpoint on mid-stream failure
- [ ] Test mocks multi-page and empty-tail
- [ ] No blind offset pagination on mutable data
## Salesforce-Specific Gotchas
1. **Apex has a 100-callout-per-transaction limit.** Paginating over thousands of pages requires Queueable chaining.
2. **QueryMore cursor expires after ~15 minutes.** Long paginations need restart logic if they straddle the expiry.
3. **`Test.setMock` supports only one response per request.** Multi-page tests need a mock class tracking call count.
## Output Artifacts
| Artifact | Description |
|---|---|
| Pagination helper Apex class | Reusable loop with safety cap |
| Rate-limit-aware http wrapper | Backoff + retry |
| Integration test fixtures | Multi-page mocks |
## Related Skills
- `integration/bulk-api-patterns` — for large-volume data operations
- `integration/rate-limit-handling` — backoff strategies
- `apex/apex-queueable-patterns` — chaining for long-running calloutsRelated Skills
mfa-enforcement-patterns
Design MFA enforcement: auto-enablement, Salesforce Authenticator rollout, exceptions, service accounts, API-only users, SSO interop, and audit. Trigger keywords: MFA, multi-factor, two-factor, Salesforce Authenticator, MFA exception, MFA SSO, api-only MFA. Does NOT cover: end-user password policies, device-trust posture, or non-Salesforce IdP configuration.
ip-relaxation-and-restriction
Design IP-based access controls: profile login IP ranges, org-wide trusted IPs, IP relaxation per profile, and the interaction with MFA and SSO. Trigger keywords: login IP range, trusted IP, IP relaxation, restricted IP, IP allowlist, login hours. Does NOT cover: network-layer firewalling, corporate VPN design, or Shield Event Monitoring.
encrypted-field-query-patterns
Design SOQL, filters, reporting, and indexes against Shield Platform Encryption fields. Trigger keywords: Shield Platform Encryption, encrypted field query, probabilistic vs deterministic encryption, encrypted SOQL filter, encrypted field index. Does NOT cover: Classic Encryption (deprecated), field-level security policy, or tenant secret key rotation.
apex-managed-sharing-patterns
Grant row-level access programmatically via __Share records when declarative sharing rules cannot express the policy. NOT for OWD, role hierarchy, or criteria-based sharing rule design.
omnistudio-testing-patterns
Use when testing or validating OmniStudio components — OmniScript preview, Integration Procedure step debugging, DataRaptor field-mapping validation, and end-to-end UTAM-based automation. NOT for Apex unit testing or standard Flow debugging.
omnistudio-error-handling-patterns
Use when designing fault behavior across Integration Procedures, DataRaptors, OmniScripts, and FlexCards — error routing, user-facing messaging, retry semantics, and idempotency. Triggers: 'omnistudio error', 'integration procedure fault', 'dataraptor error handling', 'omniscript retry', 'flexcard action failure'. NOT for general Apex exception design or Flow fault paths.
omnistudio-ci-cd-patterns
Use when designing or implementing CI/CD pipelines for OmniStudio components — DataPack export/import, versioning, environment promotion, and automated deployment. NOT for standard Salesforce metadata CI/CD or Apex-only pipelines.
omniscript-design-patterns
Use when designing or reviewing OmniScripts for guided experiences, step structure, branching, save/resume, and the boundary between OmniScript, Integration Procedures, DataRaptors, and custom LWCs. Triggers: 'omniscript design', 'too many steps in omniscript', 'save and resume omniscript', 'branching in omniscript', 'when should this be an integration procedure'. NOT for deep Integration Procedure or DataRaptor design when the guided interaction layer is not the main concern.
integration-procedure-cacheable-patterns
Use when designing Integration Procedures (IPs) with platform cache to cut latency and callout load. Covers cache key design, TTL selection, per-user vs org-wide partitions, invalidation on data changes, and safe fallback on cache miss/stale. Does NOT cover general IP authoring (see omnistudio-error-handling-patterns) or LWC client-side caching.
flexcard-design-patterns
Use when designing, building, or reviewing OmniStudio FlexCards — including data source selection, card states, actions, conditional visibility, flyout configuration, and child card iteration. Triggers: 'FlexCard', 'card template', 'flyout', 'card action', 'card state', 'data source', 'child card', 'conditional visibility'. NOT for OmniScript design, standalone LWC development, or Apex controller architecture outside the FlexCard context.
dataraptor-patterns
Use when designing or reviewing OmniStudio DataRaptors, especially Extract versus Turbo Extract versus Transform versus Load, field mapping strategy, performance tradeoffs, and when to move work into Integration Procedures or Apex. Triggers: 'DataRaptor Extract', 'Turbo Extract', 'DataRaptor Load', 'DataRaptor Transform', 'OmniStudio data mapping'. NOT for overall OmniScript journey design or Integration Procedure sequencing when the main question is not the DataRaptor shape itself.
wire-service-patterns
Use when designing or reviewing Lightning Web Components that use `@wire`, Lightning Data Service, UI API, or the GraphQL wire adapter, especially for reactive parameters, cache behavior, and refresh strategy. Triggers: 'wire service', 'refreshApex', 'reactive parameter', 'getRecord', 'wire vs imperative Apex'. NOT for component communication or generic lifecycle issues when data provisioning is not the main concern.