CareerOS Partners API

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

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