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.