Page-based — search
GET /api/jobs · POST /api/jobs/search · GET /api/companies/{id}/jobs
Request
Response
total, page, page_size, total_pages in the body. Mirrored in X-Total-Count, X-Page, X-Page-Size, X-Total-Pages — see Response headers.
Use page-based pagination for UI result pages and anything a human is looking at. Do not use it to bulk-export the corpus — use the feed. The feed is cheaper per job and immune to records shifting between pages as data changes; deep page-based pagination over a moving dataset can skip or repeat records.
Cursor-based — feed
POST /api/jobs/feed · POST /api/jobs/feed/managed · GET /api/jobs/expired
Request
Response
next_cursor, has_more in the body, mirrored by X-Has-More. Loop until has_more is false.
GET /api/auto-apply/applications also uses a cursor, with limit (default 20) in place of batch_size.
The four rules that matter
1
Send filters and batch_size only on the first request
The cursor embeds them. A continuation body carries only the cursor — any other values you send alongside it are silently ignored. This is the most common surprise: changing a filter mid-pagination does nothing.
2
Paginate serially
One in-flight request per cursor. Cursors are not designed for parallel fan-out — firing several continuations from the same cursor concurrently produces undefined results.
3
Persist next_cursor after every successful batch
So a crash resumes mid-stream instead of restarting from the beginning. See Sync a database for a full checkpointing loop.
4
Leave stable_scan at its default of true
Pages follow immutable creation time, so records cannot shift across page boundaries while you paginate — no skips, no duplicates, even if jobs are updated or expire mid-run.
Cursor failure modes
Full envelopes and retry guidance are on Errors.
Example
First request, then a continuation. Note the continuation body carries onlycursor.
Python SDK
client.search.iter_jobs(...), client.feed.iter_jobs(...), and client.feed.iter_expired_job_ids(...) handle pagination for you — page-based and cursor-based alike — yielding one item at a time.
iter_jobs on client.feed takes locations, sources, work_models, posted_after, and batch_size — it does not expose employment_types, experience_levels, updated_after, or stable_scan. Use the raw endpoints in Sync a database if you need those.
See Sync a database for the complete incremental-sync loop with checkpointing, and Errors for full error envelopes.

