Hiring signals, posted pay, and open-role counts for recruiters and staffing tools
Staffing agencies run on three questions: who is hiring in our specialty right now, what are they paying, and which of our clients' roles are still open. CleanJobData answers all three with one API. Every row is a job taken from an employer's own ATS board or career site, normalized into the same fields: the employer, title, seniority, employment type, location, posted salary, posting date, and the link to the employer's application page. Agencies use it to build prospect lists for business development, to bring market pay into client conversations, and to keep their CRM in step with what clients are actually posting. Software vendors use the same data to build those features into staffing and recruiting tools.
Run real queries in the playground without a key, or start a 14-day free trial with 300 requests a day. No card required.
Yes. Filter by your specialty and max_age=7d, e.g. `?title=software+engineer&experience_level=SE,EX&location=US&max_age=7d&limit=50`, page through next_page, and group the results by employer_id to see which companies posted several roles in that window. Add count=true to get the total match count without paging. On Starter, a job reaches you 24 hours after we index it, so this week's list is a day behind compared with Pro, which is usually fine for a weekly business development call list. Browse /feeds/senior-engineer-jobs to see what a scoped query returns before you build.
Yes. Collect each competitor's employer_id (from any of their jobs, or GET /companies?website_url=competitor.com) and pass them comma-separated, up to 100 per request, with a title or experience_level filter. You see what roles they're posting, at what seniority, and at what posted salaries. company_website_url takes one domain per request, so use it for single-company checks. That's useful context for advising clients on where they need to be competitive.
Do a first load by paging through next_page on your filtered query and storing each job by id. After that, run a daily job with created_max_age=1d, which filters on when we indexed the job rather than the employer's posted date, so jobs we index late aren't missed. Then call GET /jobs/expired?max_age=2d and mark those ids closed. Most CRMs with API access, or workflow tools like n8n, Zapier, or Make, can run this on a schedule. /guides/syncing-job-data-in-depth has the full pattern, including rate limits.
Yes, with care. salary_min and salary_max are in the employer's currency (salary_currency), and we don't convert them, so convert to one currency before you compare. There's also no pay-period field: most figures are annual, but contract and temp postings are often hourly, which salary_text will show. Filter employment_type and check salary_text before you put a number in front of a client.
Start with the free 14-day trial (300 requests a day) to check coverage for your specialty and markets; it's licensed for building and testing. Starter ($39/mo) fits daily CRM syncs and weekly prospect lists, where a 24 hours delay on new jobs doesn't change the outcome. Move to Pro ($99/mo) if recruiters need roles the day we index them or you need more volume. Compare data sources in /articles/best-job-apis-2026.
You can use what you learn from the data in client conversations and in your own tools. You can't hand clients the raw listings as an export, feed, or API on Starter or Pro; the terms treat that as redistribution, which needs an Enterprise license. If sharing data with clients is part of your service, contact us through /enterprise.