hiringindex
A Python client for the HiringIndex API. The API covers more than a million and a half live job postings, read directly from the applicant tracking systems employers hire on: Workday, SmartRecruiters, Greenhouse, Workable, Lever, Ashby, Recruitee, Teamtailor, Breezy and Personio. It has three endpoints. One searches postings with a filter, one returns aggregates over the same filter (salary percentiles, top employers, city, country and seniority splits, posting age), and one fetches a single posting by id. This package is a thin wrapper around those endpoints. It uses only the standard library, sends your filters to the API unchanged, and returns the JSON responses as plain dictionaries.
Install
pip install hiringindex
Requires Python 3.9 or newer. There are no other dependencies.
You need a RapidAPI key with a subscription to HiringIndex. Pass it to the client, or set it in the environment:
export RAPIDAPI_KEY=your-key
Quickstart
from hiringindex import HiringIndex
client = HiringIndex() # reads RAPIDAPI_KEY; or HiringIndex(api_key="...")
# Remote data engineering roles posted in the last week
page = client.search(job_titles=["Data Engineer"], remote_flag=["true"], days_ago=7, limit=20)
print(page["total_count"], "postings")
for job in page["jobs"]:
print(job["title"], job.get("company_name"), job.get("apply_url"))
# Berlin roles whose advertised yearly pay reaches EUR 60,000
page = client.search(
cities=["Berlin"],
salary={"min": 60000, "period": ["year"], "currency": ["EUR"], "match": "overlaps"},
limit=20,
)
# One posting by id: the `_id` from a search result, used verbatim
job = client.job(page["jobs"][0]["_id"])
# What the Software Engineer market looks like in San Francisco
market = client.insights(job_titles=["Software Engineer"], cities=["San Francisco"])
print(market["headline"]["row_count"], "rows,", market["headline"]["company_count"], "employers")
for band in market["salary"]: # one entry per currency and pay period
print(band["currency"], band.get("period"), band["count"], band.get("min", {}).get("p50"))
# Data Engineers in Germany and the Netherlands, one block per country
by_country = client.insights(
job_titles=["Data Engineer"],
country_codes=["DE", "NL"],
group_by="country_code",
percentiles=True,
)
for group in by_country["groups"]:
print(group["country_code"], group["row_count"])
Filters
Filters are keyword arguments with the API's own names. The client does not rename or check them.
| Key | Type | Matches |
|---|---|---|
job_titles |
list of str | the posting title |
keywords |
list of str | the title or the description; several keywords match as OR |
cities |
list of str | city names as employers write them |
country_codes |
list of str | ISO 3166-1 alpha-2 codes such as DE (a country name matches nothing) |
company_name |
str | the employer name, whole and case-insensitive |
handles |
list of str | ATS board handles, as the handle field reports them |
remote_flag |
list of str | ["true"] for remote, ["false"] for on-site |
employment_type |
list of str | as the vendor writes it |
seniority |
list of str | as the seniority field reports it |
source_platforms |
list of str | workday, greenhouse, lever, ashby and the other sources |
salary |
dict | min, max, currency (ISO 4217 list), period (list of year, month, week, day, hour), match (contains or overlaps) |
days_ago |
int | published no earlier than N days ago |
page, limit |
int | search only, 1 to 100 each |
insights takes the same filter without page and limit, plus group_by
(city, city_only or country_code), city_aliases, min_rows and
percentiles.
A key the API does not know is rejected with a 422 that lists the valid keys,
so a typo raises an error instead of returning the wrong slice. Salary amounts
are never converted between currencies, so send currency and period with a
salary filter.
Fields a source did not state are left out of a posting rather than set to
None, so read optional fields with job.get(...). remote_flag on a posting
is a string such as "true", not a boolean.
Paging
iter_jobs walks the pages for you and yields postings one at a time. It stops
after the last page, or after page 100, the furthest the API pages (so at most
100 * limit rows per filter). Each page is one request, made only when the
loop reaches it.
from itertools import islice
for job in client.iter_jobs(job_titles=["Data Engineer"], cities=["Berlin"], limit=100):
print(job["_id"], job["title"])
first_50 = list(islice(client.iter_jobs(keywords=["Kubernetes"], limit=50), 50))
Errors
Every error response raises HiringIndexError, with status, code,
message, meta and request_id attributes. Branch on code, not on
message, because the wording of messages may change.
from hiringindex import HiringIndex, HiringIndexError, KeywordTooCommon
client = HiringIndex()
try:
page = client.search(keywords=["excel"])
except KeywordTooCommon as err:
# The term matches too many postings. Narrowing by city or country does not help:
# search the role with job_titles, or use a rarer keyword.
print(err.term, err.estimated_matches, err.limit)
except HiringIndexError as err:
print(err.status, err.code, err.message, err.request_id)
| Status | code |
When |
|---|---|---|
| 400 | invalid_request |
the body is not a JSON object |
| 401, 403 | None |
missing or invalid key, or no subscription (answered by RapidAPI) |
| 404 | not_found |
job() with an id the API did not issue |
| 422 | invalid_request |
an unknown filter key or a malformed value |
| 422 | keyword_too_common |
raised as KeywordTooCommon, a subclass of HiringIndexError |
| 429 | None |
plan quota or rate limit reached (answered by RapidAPI) |
| 503 | busy |
capacity exhausted for the moment; wait err.retry_after_seconds |
| 503 | timeout |
the filter did not finish inside the API's time limit; narrow it or retry |
If no HTTP response arrives at all, for example on a connection failure or a
timeout, the standard library's OSError subclasses (urllib.error.URLError,
TimeoutError) propagate unchanged. The default timeout is 40 seconds, because
insights over a wide slice can take up to about 30 seconds on a cold cache.
Links
- API listing, plans and full reference: https://rapidapi.com/starnikovoleg/api/hiringindex
- Website: https://hiringindex.org
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hiringindex-0.1.0.tar.gz.
File metadata
- Download URL: hiringindex-0.1.0.tar.gz
- Upload date:
- Size: 11.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be1ed360982bfda1d4e117e932a1f80135c9f85ae6f1a049d5e63be5f12279eb
|
|
| MD5 |
38d1d7568232b839951ad3bece4b75c9
|
|
| BLAKE2b-256 |
fa6a592671bcd577dd6d105b0b43a3c206bbebedd5d814003410aa6f12c1dd5c
|
File details
Details for the file hiringindex-0.1.0-py3-none-any.whl.
File metadata
- Download URL: hiringindex-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fa39fad9b0c70ffb8d30952a73f1e91e2e080bee59a62d6202416d283c0251c
|
|
| MD5 |
5d61eb1e0c8db44c75a735179dfab13c
|
|
| BLAKE2b-256 |
e00813dc58d850e736543104e6a4aecf11c4ee875eac49e819a0490a748a6101
|