Career Sites Jobs API π
Pricing
from $2.70 / 1,000 job results
Career Sites Jobs API π
GET low-cost premium access to 2M+ /jobs from 120,000+ career sites & 59 ATS platforms. Real-time stream of new jobs.
Jobs API π
GET low-cost premium access to 2M /jobs from 120,000+ career sites & ATS. Ongoing real-time stream of new jobs.
2,000,000+ jobs. 59 ATS platforms. One endpoint.
The Jobs API gives you a read window into a single PostgreSQL table of jobs that we scrape continuously from 59 ATS platforms β Greenhouse, Workday, Lever, Ashby, SmartRecruiters, iCIMS, Personio, Rippling, BambooHR, Workable, Breezy, Recruitee, Teamtailor, Jobvite, Zoho, Paylocity, Paycom, Ultipro, OracleCloud, Taleo, and the rest. Every posting is parsed, normalized, scored, deduplicated, and indexed.
You get GET /api/jobs. That's the API.
The endpoint
GET /api/jobs?is_remote=true&country=United%20States&job_score_order=desc&limit=50
Response:
{"backend": "postgresql","total": 12480,"jobs": [{"id": "4819237401","slug": "4819237401","firestore_id": "4819237401","job_id": "4819237401","source_id": "greenhouse:4819237401","title": "Senior Content Writer","company_name": "Acme Co","company_type": "startup","company_logo_url": "https://logo.clearbit.com/acme.com","job_type": "writer","job_family": "Writing","subcategory": "Content Writing","workplace_type": "remote","employment_type": "FULL_TIME","experience_level": "senior","is_remote": true,"location": "Austin, Texas, United States","city": "Austin","state": "Texas","country": "United States","location_country": "United States","salary": "120000-160000","compensation": {"currency": "USD","min": 120000,"max": 160000,"period": "year"},"description": "Acme Co is hiring a Senior Content Writer to lead long-form content across our blog, docs, and customer education surfaces. You'll partner with product marketing, SEO, and design to ship 4-6 pieces a month that move pipeline and onboard users.","description_html": "<p>Acme Co is hiring a <strong>Senior Content Writer</strong> to lead long-form contentβ¦</p>","responsibilities": ["Own the editorial calendar across blog, docs, and lifecycle emails","Write 4-6 long-form pieces per month tied to pipeline and activation goals","Partner with SEO on keyword strategy and on-page optimization","Interview subject-matter experts and translate technical concepts for a developer audience","Maintain a consistent voice across surfaces, with documentation and tooling to match"],"requirements": ["5+ years writing for B2B SaaS or technical audiences","Portfolio of long-form published work with measurable outcomes","Comfort working with SEO tooling (Ahrefs, Clearscope, or similar)","Experience interviewing engineers and translating dense technical material","Native-level written English"],"benefits": ["Fully remote across the US and EU","Equity in a profitable, growing company","Unlimited PTO with a 3-week minimum","Health, dental, vision (US) / private health stipend (EU)","$2,000/year learning budget","Home office stipend","Quarterly company offsite"],"hard_skills": ["SEO", "Content Strategy", "Editorial Planning", "CMS"],"soft_skills": ["Cross-functional Collaboration", "Ownership"],"tools": ["Ahrefs", "Clearscope", "Webflow", "Notion"],"apply_url": "https://acme.com/careers/4819237401","job_score": 87,"job_score_breakdown": {"compensation": 90,"remote": 100,"freshness": 95,"company": 70,"completeness": 80},"source": "greenhouse","date_posted": "2026-07-22T15:04:11Z","created_at": "2026-07-22T16:11:09Z","image_data": {"imageFile": "https://jobs.example.com/api/jobs/4819237401/image","imageUrl": "https://jobs.example.com/screenshot/4819237401","screenshotReadyAt": "2026-07-22T16:14:02Z"}}],"limit": 50,"offset": 0,"filters": {"is_remote": "true","country": "United States","job_score_order": "desc","limit": "50","offset": "0"}}
Response envelope:
| Field | Meaning |
|---|---|
backend | The data backend ("postgresql") |
total | Total rows matching the filters, before limit/offset |
jobs | Array of job rows |
limit / offset | Echo of your pagination |
filters | Echo of every filter you sent (snake_case, canonical) |
Every response is Cache-Control: no-store, no-cache, must-revalidate β what you get is what's in the database right now. CORS is wide open (Access-Control-Allow-Origin: *).
Query parameters
| Param | Type | Default | What it does |
|---|---|---|---|
title | string | β | Case-insensitive substring (ILIKE %β¦%). title=writer matches "Senior Content Writer". |
country | string | β | Exact match on location_country. United States, Germany, β¦ |
is_remote | true / false / 1 / 0 | β | Both spellings work |
workplace_type | string | β | remote, hybrid, on_site |
employment_type | string | β | FULL_TIME, PART_TIME, CONTRACTOR |
experience_level | string | β | entry, mid, senior |
job_family | string | β | Coarse grouping (Writing, Engineering, β¦) |
company_type | string | β | startup, enterprise, agency |
source | string | β | Which ATS the row came from β greenhouse, workday, lever, β¦ |
date_posted_from | ISO timestamp | β | date_posted >= value |
date_posted_to | ISO timestamp | β | date_posted <= value |
job_score_order | asc / desc | β | Sort by quality score. Without it, you get created_at DESC, date_posted DESC (freshest first) |
limit | int (1β100) | 50 | Hard cap at 100 per page |
offset | int (0β1,000,000) | 0 | Standard pagination |
Snake_case is canonical. CamelCase aliases (workplaceType, datePostedFrom, isRemote, β¦) work too.
Pagination walk
# Page 1curl 'https://jobs.example.com/api/jobs?limit=100&offset=0'# Page 2curl 'https://jobs.example.com/api/jobs?limit=100&offset=100'# β¦keep going while jobs.length == limit, or while offset < total
Filter combinations that work well
# High-quality remote jobs posted this week, US/api/jobs?is_remote=true&country=United%20States&date_posted_from=2026-07-18&job_score_order=desc# Senior engineering roles in Germany/api/jobs?experience_level=senior&job_family=Engineering&country=Germany# All Greenhouse postings mentioning "kubernetes" in the title/api/jobs?source=greenhouse&title=kubernetes# Hybrid contractor roles at startups/api/jobs?workplace_type=hybrid&employment_type=CONTRACTOR&company_type=startup
The 59 ATS platforms
Every row in the table came from one of these. Each one has its own quirks β Greenhouse returns public job boards, Workday hides behind wd1/wd5 subdomains, Lever needs company slugs, Ashby uses posting-api/job-board/{clientname}, SmartRecruiters uses jobs-v2, iCIMS returns XML unless you pass content=false, Personio paginates with offset/limit, BambooHR needs an auth token, Rippling uses ats-api. The scraping pipeline handles all of that and normalizes the output into one schema, so you don't have to know which is which.
greenhouse, workday, lever, ashby, smartrecruiters, icims, personio, recruitee, teamtailor, workable, breezy, bamboohr, jobvite, rippling, zoho, workstream, oraclecloud, paylocity, paycom, ultipro, eightfold, comeet, gem, pinpoint, polymer, trakstar, dayforce, successfactors, taleo, hibob, adp-workforce-now, adp-myjobs, gohire, hireology, hirehive, hiringthing, jobscore, joincom, loxo, manatal, pageup, pyjamahr, recooty, applicantpro, avahr, freshteam, homerun, applytojob, easy.jobs, dover, recruitpro, catsone, candidatemanager, brassring, careerplug, careerpuck, applicantstack, apploi, harri, isolved
Every row carries its source in the source column. Filter by it to slice. Ignore it otherwise.
The job_family values
The job_family column is a closed enumeration. Use any of these values with the job_family filter β they're the canonical taxonomy the dataset is bucketed into.
Administration, Agriculture, Aviation & Maritime, Customer, Customer Support, Data, Design, Development, Education, Engineering, Finance, Government, Healthcare, Hospitality, Legal, Manufacturing, Marketing, Media & Entertainment, Mining & Resources, Operations, People, Personal Services, Product, QA & Testing, Real Estate, Research, Retail, Sales, Science & Research, Security, Skilled Trades, Sports, Veterinary, Writing
That's 34 canonical values. A handful of legacy rows still carry the older Qa spelling (a duplicate of QA & Testing) β treat them as the same. Older rows where the family hasn't been assigned yet have job_family = "unspecified".
Under each family you'll find subcategory values β those are open-ended. Writing has Content Writing, Copywriting, Technical Writing, Editing, Journalism, Translation. Development has Frontend, Backend, Full Stack, Mobile, DevOps, ML Engineering, Security Engineering, and so on. Filter by subcategory when you need that level of granularity.
What a job row looks like
The fields you'll actually use:
| Field | Type | What it is |
|---|---|---|
id / slug | text | Deterministic 10-digit numeric id, same in both |
firestore_id | text | Legacy doc id (older rows) |
job_id / source_id | text | Source-system ids |
title | text | Job title |
company_name | text | Hiring company |
company_type | text | startup, enterprise, agency |
job_type | text | Normalized bucket (writer, engineer, β¦) |
job_family | text | Coarse grouping β one of the filter facets |
subcategory | text | Finer grouping under job_family |
workplace_type | text | remote, hybrid, on_site |
employment_type | text | FULL_TIME, PART_TIME, CONTRACTOR |
experience_level | text | entry, mid, senior |
is_remote | bool | Indexed boolean β the hot filter |
location | text | Raw location string as posted |
city / state / country | text | Parsed components |
location_country | text | Canonical country used by the country filter |
date_posted | timestamptz | When the source listed it |
created_at | timestamptz | When the pipeline wrote the row |
salary | text | Raw salary line |
compensation | jsonb | Parsed {currency, min, max, period} when extractable |
job_score | numeric | 0β100 quality score |
apply_url | text | Apply link |
description / description_html | text | Raw + sanitized |
responsibilities / requirements | text | Extracted bullets (newer rows) |
hard_skills / soft_skills / tools | array | Extracted skill tags |
source | text | Which ATS β greenhouse, workday, β¦ |
image_data | jsonb | Rendered preview {imageFile, imageUrl, screenshotReadyAt} |
Indexes built for the queries that matter: (is_remote, created_at DESC), (is_remote, job_family, created_at DESC), (is_remote, location_country, created_at DESC), (is_remote, company_type, created_at DESC), (is_remote, date_posted DESC, created_at DESC), plus a GIN trigram on title. Substring search and common filter combinations stay fast as the table grows past 2M.
What you can build
A search widget on your site. Drop a country dropdown, a remote-only toggle, a job-family picker β every common filter maps to a query param. fetch('/api/jobs?β¦') and render the results. 100-row page size, paginate with offset.
A Slack or Telegram "new jobs" bot. Every hour, hit /api/jobs?date_posted_from=<one hour ago>&job_score_order=desc&limit=10. Post the top 10 to your channel. The filter does the work.
A daily email digest. Cron at 8am. date_posted_from=<yesterday>, sort by job_score_order=desc, group by job_family, render to email. Each link goes to apply_url.
A salary tracker. Pull all rows where compensation IS NOT NULL, group by location_country and job_family, average compensation.min and compensation.max. One query, structured data.
A recruiting funnel for outbound. Pull candidates with job_score_order=desc&limit=100, filter by experience_level and company_type to match your ICP, hit apply_url directly. The score sort means the top of the list is the highest-signal postings.
A vertical job board. If you're building for designers, marketers, engineers, devs, writers β filter by subcategory and you have a curated vertical feed. Add a sign-up gate, monetize the apply click.
A talent-marketplace watchlist. Save a query (is_remote=true&job_family=Engineering&country=Germany&title=staff). Hit it daily, diff against yesterday, alert your users when a match lands.
ATS migration. If you're building a job-board product, you don't need to engineer 59 scrapers yourself. Pull from this endpoint and ship your product. We already maintain the parsers, the proxies, the rate-limit handling, the de-duplication, the scoring.
For Excel File Exports
Visit jobstore.co for continous export of jobs in Excel file. Same data, same filters, build your file, and export.
Why? Community owners, online coaches, conference organizers, share jobs files with ther members. This solution makes the job sharing super simple.
What you're getting
- 2,000,000+ rows, growing continuously
- 59 ATS platforms normalized into one schema
- Query latency dominated by the index β most filter combinations return in tens of milliseconds
- CORS on, no auth on read, no rate limits on the read endpoint
no-storecache header, so polling is safe
One endpoint, one table, every job across 59 ATS platforms.