> ## Documentation Index
> Fetch the complete documentation index at: https://www.hirebase.org/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Historical Jobs Search

> Free discovery over the historical archive: counts, year breakdown, top companies, sample titles and a price quote

<Warning>
  **Rolling out.** The Historical Jobs endpoints are documented ahead of release and may not be live on `api.hirebase.org` yet. If you get a `404` or `405`, the rollout has not reached production; check the [changelog](/docs/changelog) or email [hello@hirebase.org](mailto:hello@hirebase.org) and we will let you know when it is available.
</Warning>

Find out what the historical archive holds **before you buy an export**. The archive contains every job Hirebase has seen expire (roughly 29M records) with the same structured fields as live jobs. This endpoint returns aggregate information only, so you can iterate on filters as often as you like at no cost, then hand the same filter set to [Historical Jobs Export](/docs/api-reference/jobs/historical-export).

<Info>
  **Metering:** free. Costs **0** units on every plan and every origin. Standard rate limits apply.
</Info>

<Warning>
  This endpoint requires an API key. See [Authentication](/docs/authentication).
</Warning>

## Request Body

All fields are optional, but at least one filter must be present. Unknown keys return `422` rather than being ignored. Only filters the archive index evaluates are accepted, so the count you see here is exactly the count an export will bill.

<ParamField body="job_titles" type="string[]">
  Job-title terms. Same quoting, `AND` and `-` exclusion syntax as [Search Jobs](/docs/api-reference/jobs/search-post). Example: `["sustainability", "ESG", "\"renewable energy\""]`.
</ParamField>

<ParamField body="keywords" type="string[]">
  Terms matched against `skills`, `technologies` and `benefits`. Description text is **not** searched on the archive.
</ParamField>

<ParamField body="geo_locations" type="object[]">
  Structured locations with any of `city`, `region`, `country`. Example: `[{"country": "United States"}]`.
</ParamField>

<ParamField body="location_group" type="string">
  Named region group, e.g. `Bay_Area`, `Northeast`, `Europe`.
</ParamField>

<ParamField body="company_names" type="string[]">
  Exact company names.
</ParamField>

<ParamField body="company_slugs" type="string[]">
  Company slugs, e.g. `["edf-renewables"]`.
</ParamField>

<ParamField body="date_posted_from" type="string">
  Inclusive lower bound on `date_posted`, `YYYY-MM-DD`.
</ParamField>

<ParamField body="date_posted_to" type="string">
  Inclusive upper bound on `date_posted`, `YYYY-MM-DD`.
</ParamField>

<ParamField body="date_expired_from" type="string">
  Inclusive lower bound on `date_expired`, `YYYY-MM-DD`.
</ParamField>

<ParamField body="date_expired_to" type="string">
  Inclusive upper bound on `date_expired`, `YYYY-MM-DD`.
</ParamField>

<ParamField body="sample_size" type="integer" default="50">
  Number of sample titles to return, `0`–`100`.
</ParamField>

<Note>
  Not supported on the archive (returns `422`): salary, job type, seniority, industry, work arrangement, and free-text description search. These fields are still **present in every exported record**; they just cannot be used to filter yet.
</Note>

## Response

<ResponseField name="total_count" type="integer">
  Archived jobs matching the filters. This is the number an uncapped export would contain.
</ResponseField>

<ResponseField name="by_year_posted" type="object[]">
  `{year, count}` for each year from 2021 (or `date_posted_from`) to the current year.
</ResponseField>

<ResponseField name="top_companies" type="object[]">
  Up to 10 `{company_name, count}` entries.
</ResponseField>

<ResponseField name="sample_titles" type="object[]">
  `{job_title, year_posted}` for the most recently posted matches. Titles only; full records come from the export.
</ResponseField>

<ResponseField name="coverage" type="object">
  `description_text_sample_pct`: share of the sampled records that still carry free-text description (0–100). Structured fields are retained on all records. `note`: a plain-language coverage caveat.
</ResponseField>

<ResponseField name="export_quote" type="object">
  `record_count`, `price_usd` for exporting the whole match set, and `tiers` describing the pricing.
</ResponseField>

## Coverage

The archive reflects Hirebase's own crawl footprint, which has grown year over year. A thin early year means Hirebase saw fewer postings then, not that the market was smaller.

| Year posted | Records in archive | Records with description text |
| ----------- | ------------------ | ----------------------------- |
| 2021        | \~20K              | \~57%                         |
| 2022        | \~35K              | \~57%                         |
| 2023        | \~260K             | \~57%                         |
| 2024        | \~557K             | \~57%                         |
| 2025        | \~7M               | \~20%                         |
| 2026        | \~9M and growing   | \~88%                         |

About 60% of the archive is US-based.

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST 'https://api.hirebase.org/v2/jobs/historical/search' \
    -H 'x-api-key: YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
      "job_titles": ["sustainability", "ESG", "climate", "renewable", "\"clean energy\""],
      "geo_locations": [{"country": "United States"}],
      "date_posted_from": "2023-01-01",
      "sample_size": 20
    }'
  ```

  ```python Python theme={null}
  import hirebase

  client = hirebase.Client(api_key="YOUR_API_KEY")
  res = client.jobs.historical_search(
      {
          "job_titles": ["sustainability", "ESG", "climate", "renewable", '"clean energy"'],
          "geo_locations": [{"country": "United States"}],
          "date_posted_from": "2023-01-01",
      },
      sample_size=20,
  )
  print(res["total_count"], res["export_quote"]["price_usd"])
  for row in res["by_year_posted"]:
      print(row["year"], row["count"])
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "total_count": 3096,
    "by_year_posted": [
      {"year": 2023, "count": 69},
      {"year": 2024, "count": 154},
      {"year": 2025, "count": 2857},
      {"year": 2026, "count": 16}
    ],
    "top_companies": [
      {"company_name": "Turner & Townsend", "count": 300},
      {"company_name": "EDF Renewables", "count": 117},
      {"company_name": "NextEra Energy", "count": 52}
    ],
    "sample_titles": [
      {"job_title": "Director, Global Energy and Sustainability Policy", "year_posted": 2026},
      {"job_title": "ESG Reporting Analyst", "year_posted": 2025}
    ],
    "coverage": {
      "description_text_sample_pct": 85.0,
      "note": "Archive coverage grows with Hirebase's own crawl footprint: it is dense from 2025 and sparse before that..."
    },
    "export_quote": {
      "record_count": 3096,
      "price_usd": 182.88,
      "tiers": "$0.12/record for the first 1,000; $0.03 for the next 9,000; $0.01 for the next 90,000; $0.001 thereafter. $0.50 minimum."
    }
  }
  ```
</ResponseExample>
