Jobo Enterprise — Python Client
Access millions of job listings, enriched company profiles, and geocoding — all from a single API.
Features
| Sub-client | Property | Description |
|---|---|---|
| Jobs Feed | client.feed |
Bulk and managed job feeds with cursor-based pagination (106 ATS) |
| Jobs Search | client.search |
Full-text search, filters, facets, and single-job lookup |
| Companies | client.companies |
Enriched company profiles and per-company job listings |
| Locations | client.locations |
Geocode location strings into structured coordinates |
Both sync (JoboClient) and async (AsyncJoboClient) are included.
Get your API key → enterprise.jobo.world/api-keys
Installation
pip install jobo-enterprise
Quick Start
from jobo_enterprise import JoboClient
with JoboClient(api_key="your-api-key") as client:
# Search for jobs
results = client.search.search(q="software engineer", location="San Francisco")
for job in results.jobs:
print(f"{job.title} at {job.company.name}")
# Geocode a location
geo = client.locations.geocode("London, UK")
print(f"{geo.locations[0].display_name}: {geo.locations[0].latitude}, {geo.locations[0].longitude}")
Authentication
client = JoboClient(api_key="your-api-key")
Jobs Feed — client.feed
Bulk-sync millions of active jobs using cursor-based pagination.
Fetch a batch
from jobo_enterprise import LocationFilter
response = client.feed.get_jobs(
locations=[
LocationFilter(country="US", region="California"),
LocationFilter(country="US", city="New York"),
],
sources=["greenhouse", "workday"],
work_models=["remote", "hybrid"],
batch_size=1000,
)
print(f"Got {len(response.jobs)} jobs, has_more={response.has_more}")
Auto-paginate all jobs
for job in client.feed.iter_jobs(batch_size=1000, sources=["greenhouse"]):
save_to_database(job)
Incremental sync
After the initial backfill, pass updated_after to pick up only what changed.
Scans page by immutable creation time by default (stable_scan), so records
cannot shift across page boundaries while you are reading.
from datetime import datetime, timedelta, timezone
since = datetime.now(timezone.utc) - timedelta(hours=1)
for job in client.feed.iter_jobs(updated_after=since, batch_size=1000):
upsert(job)
Managed feed
Jobs from the companies you configured through Managed Job Scraping in the
Jobo portal. Same batch and cursor semantics, minus the locations filter.
for job in client.feed.iter_managed_jobs(batch_size=1000):
save_to_database(job)
Expired job IDs
expired_since is optional and defaults to 24 hours ago. Maximum lookback is 7 days.
for job_id in client.feed.iter_expired_job_ids():
mark_as_expired(job_id)
Jobs Search — client.search
Full-text search with filters and page-based pagination.
Simple search
from jobo_enterprise import WorkModel
results = client.search.search(
q="data scientist",
location="New York",
sources="greenhouse,lever",
work_model=WorkModel.REMOTE, # or just "remote"
min_salary_usd=120000,
page_size=50,
)
print(f"Found {results.total} jobs across {results.total_pages} pages")
Closed value sets. Parameters with a fixed set of accepted values ship as enums for discoverability —
WorkModel,EmploymentType,ExperienceLevel,CompensationPeriod, andSkillType. Each member subclassesstr, so passing the equivalent literal (e.g."remote") is always valid too. Values are lowercase and hyphenated ("full-time","per-diem"); the API matches them exactly, so a misspelt value simply matches nothing.
Fetch one job
job = client.search.get_job("a1b2c3d4-e5f6-7890-abcd-ef1234567890")
Unmetered — this endpoint deducts no credits, which makes it a cheap way to wire up an integration.
Trim the payload
Omit include_fields for the whole job, pass a subset to keep only those heavy
fields, or pass an empty value for core fields only.
results = client.search.search(q="data scientist", include_fields="summary", page_size=50)
Advanced search (typed filters & facets)
from jobo_enterprise import InclusionExclusionFilter, RangeFilter
results = client.search.search_advanced(
queries=["machine learning engineer", "ML engineer", "AI engineer"],
locations=["San Francisco", "New York"],
sources=["greenhouse", "lever", "ashby"],
work_models=["remote", "hybrid"],
skills=InclusionExclusionFilter(include=["python"], exclude=["php"]),
salary_usd=RangeFilter(min=150000),
include_facets=["work_model", "experience_level"],
page_size=100,
)
for facet, buckets in results.facets.items():
print(facet, [(b.key, b.count) for b in buckets])
Auto-paginate all results
for job in client.search.iter_jobs(
queries=["backend engineer"],
locations=["London"],
page_size=100,
):
print(f"{job.title} — {job.company.name}")
Companies — client.companies
Fetch fully enriched company profiles and list jobs scoped to a company.
company = client.companies.get(job.company.id)
print(company.name, company.website, company.industries)
# Jobs for a single company (paginated)
jobs = client.companies.get_jobs(job.company.id, page_size=50)
print(f"{jobs.total} jobs at {company.name}")
Locations — client.locations
Geocode location strings into structured data with coordinates.
result = client.locations.geocode("San Francisco, CA")
for location in result.locations:
print(f"{location.display_name}: {location.latitude}, {location.longitude}")
Auto Apply
Not covered by this client. The Auto Apply contract is profileless and callback-driven, and application creation is not yet open to traffic. Call it over plain HTTPS — see the Auto Apply reference.
Async Support
Every sub-client has an async equivalent via AsyncJoboClient:
import asyncio
from jobo_enterprise import AsyncJoboClient
async def main():
async with AsyncJoboClient(api_key="your-api-key") as client:
# Search
results = await client.search.search(q="frontend developer")
# Auto-paginated feed
async for job in client.feed.iter_jobs(batch_size=500):
await process_job(job)
# Geocode
geo = await client.locations.geocode("Berlin, DE")
asyncio.run(main())
Error Handling
429 and 503 are retried for you with bounded backoff, honouring
Retry-After. Everything else raises immediately, as a subclass of JoboError:
from jobo_enterprise import (
JoboAuthenticationError,
JoboPermissionError,
JoboNotFoundError,
JoboRateLimitError,
JoboValidationError,
JoboCursorRestartRequiredError,
JoboServerError,
JoboError,
)
try:
results = client.search.search(q="engineer")
except JoboAuthenticationError:
print("Invalid API key")
except JoboPermissionError:
print("Key is not entitled to this resource")
except JoboNotFoundError:
print("No such job or company")
except JoboRateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
except JoboValidationError as e:
print(f"Bad request: {e.detail} ({e.code})")
except JoboCursorRestartRequiredError:
print("Feed cursor is spent — discard it and start a new scan")
except JoboServerError:
print("Server error — try again later")
Every exception carries the API's machine-readable problem code when one is
supplied, alongside status_code, detail, and the raw response_body.
Supported ATS Sources (106)
| Category | Sources |
|---|---|
| Enterprise ATS | workday, smartrecruiters, icims, successfactors, oraclecloud, taleo, dayforce, csod, adp, ultipro, paycom |
| Tech & Startup | greenhouse, lever_co, ashby, workable, workable_jobs, rippling, polymer, gem, pinpoint, homerun |
| Mid-Market | bamboohr, breezy, jazzhr, recruitee, personio, jobvite, teamtailor, comeet, trakstar, zoho |
| SMB & Niche | gohire, recooty, applicantpro, hiringthing, careerplug, hirehive, kula, careerpuck, talnet, jobscore |
| Specialized | freshteam, isolved, joincom, eightfold, phenompeople |
The full catalogue of 106 providers is listed in the
API documentation. Treat it as an open set —
new provider_id values appear as platforms are added.
Configuration
| Parameter | Default | Description |
|---|---|---|
api_key |
required | Your API key |
base_url |
https://connect.jobo.world |
API base URL |
timeout |
30.0 |
Request timeout (seconds) |
feed_timeout |
120.0 |
Response timeout for the feed routes |
httpx_client |
None |
Custom httpx client |
Use Cases
- Build a job board — Search and display jobs from 106 ATS platforms
- Job aggregator — Bulk-sync millions of listings with the feed endpoint
- ATS data pipeline — Pull jobs from Greenhouse, Lever, Workday, etc. into your data warehouse
- Recruitment tools — Power candidate-facing job search experiences
- Company intelligence — Enrich listings with funding, headcount, and tech-stack data
- Location intelligence — Geocode and normalize job locations
Links
- Website — jobo.world/enterprise
- Get API Key — enterprise.jobo.world/api-keys
- GitHub — github.com/Prakkie91/jobo-python
- PyPI — pypi.org/project/jobo-enterprise
License
MIT — see LICENSE.
Metadata
Release files for jobo-enterprise 4.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jobo_enterprise-4.0.0.tar.gz | 28.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jobo_enterprise-4.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.8 kB
Release files / jobo_enterprise-4.0.0.tar.gz
| Download URL | jobo_enterprise-4.0.0.tar.gz |
|---|---|
| Size | 28.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e04939e7ba19544ad2f24e8abdca9ebaa5248579edcc3e1df3dcdc7253126666
|
|
BLAKE2b-256 checksum How to use checksums |
5ce4af58e0d6500cc1ac78b7389c1cb9e461f604c7cd0b6169b6442241d7e6f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Release files / jobo_enterprise-4.0.0-py3-none-any.whl
| Download URL | jobo_enterprise-4.0.0-py3-none-any.whl |
|---|---|
| Size | 24.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6ec69050f689c21cbbdec13c6a87a84c31d5670fb3855651e1864551811d4a7b
|
|
BLAKE2b-256 checksum How to use checksums |
69e39e497efced8eb7a809dc4a8a91d4e3ea82319c31939555fe474ed9c77428
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|