Skip to main content

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

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

hiringindex-0.1.1.tar.gz (12.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hiringindex-0.1.1-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file hiringindex-0.1.1.tar.gz.

File metadata

  • Download URL: hiringindex-0.1.1.tar.gz
  • Upload date:
  • Size: 12.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hiringindex-0.1.1.tar.gz
Algorithm Hash digest
SHA256 98ab58264a145d3651bfb982ba236b20daed14de9a278a7d1798d0d25fe8cc38
MD5 6c84b4e589aff02b53f1faf268e47f48
BLAKE2b-256 f75cf9126815bb9c9db075df3a3aa7c20e995f104ab178dc3a7d62d2a5e7079c

See more details on using hashes here.

Provenance

The following attestation bundles were made for hiringindex-0.1.1.tar.gz:

Publisher: publish.yml on starnikov-oleg-org/hiringindex-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hiringindex-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: hiringindex-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hiringindex-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9a1a5fac5eb642f8656f7ff30f5933419027f460dc8d27932be8dd0f3db24513
MD5 6b2d5be9bf68256b2bb41d773f659343
BLAKE2b-256 ea2bb16439e8c730a07da2bbdc3e64bff61df7468f9377fdfccb7681b1fb7c7b

See more details on using hashes here.

Provenance

The following attestation bundles were made for hiringindex-0.1.1-py3-none-any.whl:

Publisher: publish.yml on starnikov-oleg-org/hiringindex-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page