Job Postings
Open job-posting counts for a curated set of companies, captured over time.
job_postings — the dataset name to pass to the Obscura API.
What one row means
One curated public company's open-requisition count on its public Applicant Tracking System (ATS) board (Greenhouse or Lever), as scraped on a given calendar day — the row IS the snapshot, not a report of an event that happened earlier.
One row per (ticker, captured_date).
Point-in-time availability
Every Obscura dataset carries available_date: the calendar day the publisher made the row
available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the
same thing on every dataset in the catalog.
For job_postings: snapshot: available_date = captured_date, a STORED GENERATED column. WHY THAT IS THE DAY IT BECAME AVAILABLE: the Greenhouse/Lever board APIs serve the CURRENT requisition list and keep no history, so the open-jobs count for a past day cannot be fetched — the day the collector scraped the board is the day that count was obtainable. The column was called `posted_on` until migration 000205: it never held the day a vacancy was posted, it held the day WE looked, and the name made an availability audit classify it as a source date.
Refresh cadence
Obscura refreshes job_postings daily — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.
Schema — 6 columns
The full public column list for job_postings, with the meaning of every field. The same
schema is served unauthenticated at https://api.obscura.trade/v1/catalog/job_postings.
| Column | Type | Description |
|---|---|---|
| ticker | text · not null | Stock ticker of the curated public company whose ATS board was scraped (e.g. COIN, DASH, ABNB, GTLB, DDOG, NET, AFRM, NFLX). Sourced from the hardcoded BOARDS list in job_postings.rs, not looked up dynamically; half of the primary key with captured_date. |
| captured_date | date · not null | The calendar day the collector SCRAPED the board and captured the open_jobs count, set to `Utc::now().date_naive()` once per task run. Other half of the primary key with ticker; the ON CONFLICT target for upsert, and the column available_date is generated from — the ATS APIs serve only the current requisition list, so the day we looked is the day the count was obtainable. NOT the day any vacancy was posted, which the column's old name (`posted_on`, until migration 000205) wrongly implied. |
| source | text · not null | Which ATS platform's API served this board's job list: 'greenhouse' (boards-api.greenhouse.io) or 'lever' (api.lever.co). Set from Source::label() in job_postings.rs; determines the parsing shape used (Greenhouse returns an object with a `jobs` array, Lever returns a bare array). |
| board_token | text · not null | The company's slug/token on its ATS platform, used to build the API URL (e.g. 'coinbase' -> boards-api.greenhouse.io/v1/boards/coinbase/jobs, 'netflix' -> api.lever.co/v0/postings/netflix). Hardcoded per-ticker in the BOARDS const in job_postings.rs; a renamed or retired token causes a 404 which is logged and skipped rather than failing the whole run. |
| open_jobs | integer · not null | Count of currently open requisitions on the company's public ATS board at scrape time — the length of the `jobs` array (Greenhouse) or the top-level array (Lever) returned by the API with `content=false`/`mode=json` (job listing metadata only, no descriptions fetched). This is the hiring-intensity signal itself, not a rate or delta; comparing open_jobs across consecutive captured_date rows for the same ticker is how a caller derives net-hiring trend. |
| available_date | date | PUBLIC-availability date = the scrape day, generated directly from `captured_date`. DB-generated, read-only; a live snapshot has no separate 'period' it describes — the point-in-time column to filter/join on. |
Access job_postings
Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.
import obscura
client = obscura.Client("obs_live_…")
df = client.query(
dataset="job_postings",
symbols=["NVDA", "AAPL"],
start="2024-01-01",
)
Create a free account Browse all 95 datasets
Frequently asked questions
What is in the job_postings dataset?
Open job-posting counts for a curated set of companies, captured over time. One curated public company's open-requisition count on its public Applicant Tracking System (ATS) board (Greenhouse or Lever), as scraped on a given calendar day — the row IS the snapshot, not a report of an event that happened earlier.
How do I avoid look-ahead bias with job_postings?
Filter on job_postings.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — snapshot: available_date = captured_date, a STORED GENERATED column. WHY THAT IS THE DAY IT BECAME AVAILABLE: the Greenhouse/Lever board APIs serve the CURRENT requisition list and keep no history, so the open-jobs count for a past day cannot be fetched — the day the collector scraped the board is the day that count was obtainable. The column was called `posted_on` until migration 000205: it never held the day a vacancy was posted, it held the day WE looked, and the name made an availability audit classify it as a source date. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.
In what formats can I get job_postings?
As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="job_postings". The column schema is public at https://api.obscura.trade/v1/catalog/job_postings.
Can I filter job_postings by company or symbol?
Yes. job_postings carries ticker, the column the API's symbols filter resolves against.
How often is job_postings updated?
Obscura refreshes job_postings on a daily schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.