Skip to main content
hirebase-python-sdk
A lean, typed Python client for the [Hirebase API](https://docs.hirebase.org/) — search jobs and companies, run market insights, and export job data at scale.
  • Sync and async clients (hirebase.Client / hirebase.AsyncClient).
  • Typed by default — responses come back as Pydantic models; pass return_type=dict anywhere for raw dicts.
  • Streaming exports — kick off an export, poll it, download it, and stream millions of jobs without loading them into memory.
  • Self-contained — the SDK ships its own types and depends only on requests, httpx, and pydantic.

Guides: Getting started · Jobs · Companies · Resumes · Tasks · Errors · Examples

Installation

pip install hirebase

# Optional extras
pip install "hirebase[streaming]"   # ijson, for streaming JSON-array exports
pip install "hirebase[cli]"         # the bundled `hirebase` command-line tool

Authentication

Pass your API key directly, or set it via the environment:

import hirebase
client = hirebase.Client(api_key="sk_live_...")
export HIREBASE_API_KEY="sk_live_..."
export HIREBASE_BASE_URL="https://api.hirebase.org"   # optional, this is the default

Resolution order for every setting is argument → environment variable → default. The base URL defaults to https://api.hirebase.org.

Quickstart

import hirebase

client = hirebase.Client(api_key="sk_live_...")

# Search jobs — results are typed and iterable
result = client.jobs.search({
    "job_titles": ["Software Engineer", "Product Engineer"],
    "locations": [{"city": "San Francisco", "region": "California",
                   "country": "United States"}],
    "limit": 20,
})

print(result.total_count, "matches")
for job in result:
    print(job.job_title, "@", job.company_name, "—", job.salary_range)

Booleans are accepted natively (visa=True), and locations is a friendly alias for the API's geo_locations. Unknown filter keys are passed through untouched, so new API features work before the SDK is updated.

Async

import asyncio, hirebase

async def main():
    async with hirebase.AsyncClient(api_key="sk_live_...") as client:
        result = await client.jobs.search({"job_titles": ["Engineer"]})
        for job in result:
            print(job.job_title)

asyncio.run(main())

Every method has the same signature on both clients — the async versions are awaitable.

Jobs

# Search
result = client.jobs.search(query, page=1, limit=20)

# Fetch one job
job = client.jobs.get("6958cfd211e2763c3491ef8b")

# Market insights for a cohort (same filter shape as search)
insights = client.jobs.insights({"job_titles": ["Data Scientist"]})
print(insights.headline.median_salary, insights.salary.p90)

Typed inputs

You can pass a plain dict or build a typed query:

from hirebase import JobQuery, SalaryRange

query = JobQuery(
    job_titles=["Backend Engineer"],
    salary=SalaryRange(min=150_000, currency="USD"),
    location_types=["Remote"],
    visa=True,
)
result = client.jobs.search(query)

Exporting jobs (async task flow)

Exports are processed server-side and returned as a downloadable file.

query = {
    "job_titles": ["Software Engineer", "Product Engineer", "Fullstack Engineer"],
    "locations": [{"city": "San Francisco", "region": "California",
                   "country": "United States"}],
}

# 1. Start the export -> returns a Task
task = client.jobs.export(query, format="json")   # or format="csv"

# 2. Poll until it finishes -> (success, result)
success, result = client.tasks.poll(task)
if not success:
    raise RuntimeError(f"Export failed: {result.error}")

# 3. Download the file (streamed to disk)
client.stream_file(result["download_url"], file_path="./jobs.json")

# 4. Stream jobs from the file (typed by default; uses constant memory)
for job in client.jobs.stream_file("./jobs.json"):
    print(job.job_title)

# ...or get raw dicts
for row in client.jobs.stream_file("./jobs.json", return_type=dict):
    ...

poll() accepts a Task, a task dict, or a task id, plus interval, timeout, and an on_progress callback. The result dict contains download_url, file_size, record_count, and expiry_time.

You can also stream directly from the export URL without saving to disk (JSON Lines exports only):

for job in client.jobs.stream_url(result["download_url"]):
    print(job.job_title)

Hiring manager contacts (async task flow)

Requires the hiring_manager_api feature on your key (email spencer@hirebase.org). Research returns name, role and LinkedIn profile per contact; email and phone are optional reveals billed only when found.

task = client.jobs.contacts("6ab32db8f1c329e432f72994")          # LinkedIn only
task = client.tasks.poll(task.id, timeout=600)
for c in task.result["contacts"]:
    print(c["name"], c["role"], c["profile_url"])

# Reveal one contact you picked (work email by default, phone on request)
reveal = client.jobs.reveal_contact(c["profile_url"], name=c["name"], reveal_phone=True)
reveal = client.tasks.poll(reveal.id, timeout=300)
print(reveal.result["email"], reveal.result["phone_number"])

# Or reveal every contact of a posting up front
task = client.jobs.contacts("6ab32db8f1c329e432f72994", reveal_email=True, reveal_phone=True)

Companies

# Search
companies = client.companies.search({"company_name": "Stripe"})
for company in companies:
    print(company.company_name, company.company_slug)

# Get a company by slug — optionally with its jobs and live insights
company = client.companies.get("stripe", return_jobs=True, return_insights=True)
print(company.description_summary)
print(company.insights_data.headline.total_count)

# Bound helpers (the object remembers its client)
insights = company.insights()
jobs = company.get_jobs(limit=10)

# Company-scoped insights directly
insights = client.companies.insights("stripe", query={"days_ago": 30})

Typed vs. dict responses

Every method returns typed models by default. Pass return_type=dict to get the raw API payload instead:

data = client.jobs.search(query, return_type=dict)   # -> dict
job  = client.jobs.get(job_id, return_type=dict)      # -> dict

Errors

All errors subclass hirebase.HirebaseError:

Exception Meaning
ConfigurationError No API key / bad config
AuthenticationError 401 — invalid API key
PaymentRequiredError 402 — plan/credits required
PermissionError_ 403 — not allowed
NotFoundError 404
RateLimitError 429 from the request limiter (100 requests / 60 s per key); check err.retry_after
QuotaExceededError 429 with X-Billing-Code: limit_exceeded: the plan's included allowance is used up. Subclass of RateLimitError; err.usage holds the quota snapshot
ServerError 5xx
APIError any other non-2xx (.status_code, .message, .body)
TaskFailed / TaskTimeout export task failed or timed out
import hirebase

try:
    client.jobs.search(query)
except hirebase.RateLimitError:
    ...
except hirebase.APIError as e:
    print(e.status_code, e.message)

Tracking quota without polling

Every metered response carries Hirebase-Usage-* headers. Pass return_meta=True to any metered method (jobs and companies, sync or async) to get them back with the result as a ResponseMeta:

jobs, meta = client.jobs.search({"job_titles": ["Software Engineer"]}, limit=50, return_meta=True)
usage = meta.usage                      # None on un-metered endpoints
print(usage.meter, usage.total_used, "/", usage.included_limit, "remaining:", usage.included_remaining)
if usage.is_meter_mode and usage.overage_used:
    print("billing overage units:", usage.overage_used)
print(meta.status_code, meta.request_id)  # transport details for the same call

Without the flag the return shape is unchanged, so existing code keeps working.

When a block-mode plan is at its cap the API refuses the call with a 429 that is not a rate limit, so backing off will not help:

try:
    client.jobs.search(query, limit=100)
except hirebase.QuotaExceededError as err:
    remaining = err.usage.included_remaining   # e.g. 2 -> retry with limit=2
except hirebase.RateLimitError as err:
    time.sleep(err.retry_after or 5)           # the 100 req / 60 s limiter

Development

pip install -e ".[dev]"

# Offline unit tests (no network)
pytest

# Live integration tests against the real API
HIREBASE_API_KEY=sk_live_... pytest tests/test_integration.py -v

If your environment preloads conflicting pytest plugins, run with PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 pytest.

License

MIT — see LICENSE.

Release files for hirebase 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hirebase 0.2.2
File Size Uploaded
hirebase-0.2.2.tar.gz 67.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hirebase 0.2.2
File Interpreter ABI Platform
hirebase-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 136.8 kB

Release files / hirebase-0.2.2.tar.gz

Download URL hirebase-0.2.2.tar.gz
Size 67.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d3fb5b3c0e49661b168b22c57bf8cd8331ab34c07401219efad43af654da8d8b
BLAKE2b-256 checksum
How to use checksums
f22333450a44ba310c522f4ed500c773b5446ef377082dfd460389a96c059622
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / hirebase-0.2.2-py3-none-any.whl

Download URL hirebase-0.2.2-py3-none-any.whl
Size 69.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9ba267a19387fb3d079194d4bc99790f1049ae16e14c56e1e8f7b3ffcd28b6b4
BLAKE2b-256 checksum
How to use checksums
a6e8ac5a9a1195614f129466d6c1b3614f2128ce753506142549a0114caec975
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.1.1

2 release 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