Filtering & pagination
Every list endpoint supports the same query language. Any column in a resource’s schema is filterable.
Filter operators
?status=eq.active equals
?graduation_date=gte.2026-01-01 greater-than-or-equal
?graduation_date=lte.2026-12-31 combine params = AND
?intake_year=eq.2025 numbers work the same way
?title=ilike.*consultant* case-insensitive pattern (* = wildcard)
?id=in.(uuid1,uuid2,uuid3) IN list
?email=not.is.null NOT NULL
?university_ids=cs.{uuid} array contains (uuid[] columns)
?or=(all_cohorts.eq.true,cohort_ids=cs.{uuid}) OR groups
This is standard PostgREST syntax — the full operator set works, the table above is what partners use most.
Projection & sorting
?select=id,first_name,email only these columns
?order=last_name.asc sort
?order=score.desc.nullslast sort with NULL placement
Use select= aggressively on resources with large columns (resumes.content, jobs.description, student_profiles.sections) — it’s the difference between kilobytes and megabytes per page.
Pagination
GET /v1/resumes?limit=100&offset=0 first page
GET /v1/resumes?limit=100&offset=100 next page
The HTTP Range: 0-99 header style also works, but query params are simpler.
Total counts
Add Prefer: count=exact and the response’s Content-Range header carries the total:
Content-Range: 0-99/16980
This costs a count query on large datasets — only request it when you need it.
Hard limits
- Server cap: 10,000 rows per response.
?limit=999999silently truncates to 10,000. - If you omit
limityou get up to 10,000. Always passlimitin production code. - Rate limit: 600 requests/min per source IP. For initial bulk syncs, page at
limit=1000with ~100 ms between requests — a comfortable 60k rows/min.
Keyset pagination for deep pages
Past offset ~5,000, LIMIT/OFFSET gets slow (the database scans through the offset). Switch to keyset pagination:
GET /v1/resumes?order=id.asc&limit=1000 first page
GET /v1/resumes?id=gt.<last_id_of_prev_page>&order=id.asc&limit=1000