Guide / Jobs API

Building a reliable job-market data pipeline

A dependable jobs dataset needs more than a list of URLs. It needs stable identity, explicit freshness, source provenance, careful normalization, and an incremental boundary you can resume.

01 / THE MODEL

Treat job data as a changing index, not a pile of pages

Employer career sites are optimized for applicants reading one board. A market-data product has a different job: compare many companies, preserve source identity, normalize only defensible fields, and keep the collection current without rebuilding it on every request.

Clair separates background collection from public search. Your integration reads one bounded schema across supported ATS platforms; the response still tells you which provider, board, and external ID each record came from.

02 / SYNC

Increment on Clair discovery time

For alerts and warehouse ingestion, filter with first_seen_after, sort by first_seen_at, and retain meta.next_cursor. The cursor is bound to the complete filter and sort contract, so changing a filter while reusing it fails explicitly.

GET /v1/jobs?first_seen_after=2026-08-01T00:00:00Z\n    &sort=first_seen_at\n    &country=DE\n    &limit=100

Publisher time answers a different question. posted_at may be missing or reflect a source-side update; first_seen_at is the stable observation boundary for your own pipeline.

03 / FRESHNESS

Keep record freshness separate from index health

Each job has a last_verified_at. Each response also reports index-level status, the latest successful crawl time, and active and stale board counts. One tells you about a record; the other tells you whether coverage is operating normally.

Do not translate either field into a promise that an application is still available. Link back to posting_url or apply_url, and show the verification time when users make time-sensitive decisions.

04 / NORMALIZATION

Preserve unknowns and provenance

Normalization is useful only when it does not turn uncertainty into confident-looking data. A missing employment type, country, salary, or publication date stays null. Compensation retains its currency and interval; Clair does not silently annualize or convert it.

The nested compensation source distinguishes an ATS field from a figure extracted out of employer-written prose. Keep that marker in your database so analysis can include, exclude, or weight derived values deliberately.

05 / IDENTITY

Use stable IDs without hiding the source

Store the Clair ID as your ingestion key and retain the complete source object beside it. Provider-aware deduplication avoids merging different roles merely because their titles look alike, while source identity makes a result auditable when a board changes.

Exact totals are opt-in because counting canonical postings has a real query cost. A streaming job normally needs has_more and the next cursor; an analytics snapshot can request include_total=true when the count itself is part of the output.

06 / BOUNDARIES

Job data is not hiring advice or an application system

Search results describe published postings and Clair processing state. They do not validate an employer, guarantee availability, rank a candidate, or submit an application. The employer source remains the place to confirm details and apply.

If you are deciding whether to use this index or maintain source adapters yourself, read the direct ATS comparison.

07 / FAQ

Questions from data teams

Does a search request contact employer career sites?

No. Clair refreshes its board registry asynchronously. Public requests search a prepared index, so request latency and availability are not tied to an employer site responding at that moment.

Should I sync by posted_at or first_seen_at?

Use first_seen_at for incremental discovery because Clair always knows when it first observed a record. Use posted_at for publisher-time research, while allowing for sources that omit it.

Does a missing salary mean the role is unpaid?

No. Null means the source did not state a usable value or Clair could not derive one safely. It is an unknown value, not zero.

Is last_verified_at a guarantee that a job is still open?

No. It records the latest successful crawl that still contained the posting. Use it with the response-level index status and follow the source link when current availability matters.

Build on one normalized jobs contract

Search prepared postings across ATS platforms, retain their provenance, and continue your ingestion loop with a cursor bound to the exact filters you chose.