# ADP Jobs API: 103,000 Job Listings, No Company List (`glitchbound/adp-jobs-api`) Actor

Search 103,000 open roles across 325 company ADP job boards at once, without knowing a company name. From the employer's own board: no login, no cookies. Poll it for what is new.

- **URL**: https://apify.com/glitchbound/adp-jobs-api.md
- **Developed by:** [Daniel Meshulam](https://apify.com/glitchbound) (community)
- **Categories:** Jobs, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.60 / 1,000 job postings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ADP Jobs API: Search Every ADP Board At Once

Search open roles across every **ADP** job board in the index at once,
without knowing a single company name.

Every row comes from the employer's own ADP job board API, the one they
publish so job aggregators can syndicate it. **There is no login, no cookies
to hand over, and no account of yours in the loop.**

Most tools that read ADP ask you for a board token first, which only works
if you already have the list. That is the hard part. This one holds the index,
so you ask a question instead:

> senior backend engineers in Berlin, remote, not internships

### Search in one call

Ask for the roles you want across every ADP board in the index:

```json
{
  "title": [
    "data engineer"
  ],
  "location": [
    "berlin",
    "remote"
  ],
  "workArrangements": [
    "remote",
    "hybrid"
  ],
  "postedAfter": "2026-08-01",
  "maxResults": 200
}
```

Or switch to **companies** mode to get the employers behind the postings, one row each, with how fast they are hiring:

```json
{
  "mode": "companies",
  "hiringLabels": [
    "surging",
    "growing"
  ],
  "minOpenedLast30": 10,
  "maxResults": 100
}
```

### What you get per job

One row per open role. A real row from this index:

```json
{
  "title": "Vice President, Construction & Development, North Bay",
  "company": "The Bay Club Company",
  "location": "San Francisco, California, United States",
  "department": "Facilities Management",
  "url": "https://myjobs.adp.com/bayclubexternal/cx/job-details?reqId=5001226162506",
  "jobId": "5001226162506",
  "platform": "adp",
  "postedAt": "2026-09-18T00:26:56Z",
  "seniority": "executive",
  "employmentType": "full-time",
  "workArrangement": "onsite",
  "country": "United States",
  "city": "San Francisco"
}
```

### Input reference

| Field | What it does |
|---|---|
| `mode` | Jobs returns one row per open role. |
| `title` | Words that must appear in the job title, one per line. |
| `titleExactWords` | Off by default. |
| `location` | Places to match, one per line, e.g. |
| `countries` | Only roles in these countries, matched on a country resolved from the employer's location string rather than on the text itself. |
| `company` | Company or board names to match, one per line. |
| `department` | Departments or teams to match, one per line, e.g. |
| `keywords` | Search title, company, location and department together, one term per line. |
| `titleExclude` | Drop roles whose title contains any of these, one per line, e.g. |
| `companyExclude` | Drop jobs from these companies, one per line. |
| `locationExclude` | Drop jobs in these places, one per line. |
| `workArrangements` | Remote, hybrid or on-site. |
| `seniority` | Derived from the job title, because no ATS publishes a seniority field. |
| `employmentTypes` | Full-time, contract, part-time, temporary or internship. |
| `postedAfter` | An ISO date, e.g. |
| `changedSince` | An ISO date, e.g. |
| `withSalaryOnly` | Keep only roles where the employer published a pay band. |
| `minAnnualSalary` | Only roles whose published lower bound is at least this, per year. |
| `maxAnnualSalary` | Only roles whose published lower bound is at most this, per year. |
| `salaryCurrency` | Restrict to bands published in these currencies. |
| `maxResults` | A hard ceiling on jobs returned and charged. |
| `hiringLabels` | Surging is the top 1% of companies by roles opened in 30 days, growing the top 10%, steady everything else that is hiring, quiet nothing new. |
| `minOpenedLast30` | Only companies that opened at least this many roles in the last 30 days. |
| `minOpenedLast7` | Only companies that opened at least this many roles in the last 7 days. |
| `minOpenRoles` | Filters out companies with only a handful of postings. |
| `enteringNewDepartments` | Only companies whose recent postings are in a department they were not hiring for before. |
| `withContactOnly` | Only companies whose own website publishes a way to reach them: a role address like info@ or sales@, a phone number from a tel: link, or the company's own socia |
| `includeStaffingAgencies` | Staffing agencies and recruiters post enormous volumes on behalf of other companies and dominate any hiring ranking, so they are excluded by default in Companie |

Rows your filters drop are never charged, and `maxResults` caps what a run can return and bill. The exact price per job is on the **Pricing** tab.

### Poll it for what changed

`changedSince` takes an ISO date and returns only postings this index first
SAW on or after it, so consecutive runs tile with no gap and no overlap. That
is the field to sync on, not `postedAfter`, which reads the date the employer
typed and moves when they edit or repost.

`mode: closed` returns roles this index watched **disappear**, with the day
they went. No job board publishes that: a board serves what is open, so what
vanished only exists if something looked yesterday too.

### Honest limits

**restaurant and retail groups, franchise operators, clinics and non-profits, from the ADP career site API.**

Coverage is every ADP board this index has found and verified, rebuilt
nightly. It is not every ADP board that exists, and no source can promise
that: there is no public directory of them.

A row we could not classify is left **unlabelled** rather than guessed into a
bucket, so filtering on a label narrows to rows that actually carry it.

### Need more than ADP?

The **Jobs Search API** searches all of these at once and returns rows in this
exact shape, so the two can be concatenated: Greenhouse, Ashby, Workable,
Recruitee, Personio, Rippling, BambooHR, Breezy and Teamtailor.

# Actor input Schema

## `mode` (type: `string`):

Jobs returns one row per open role. Companies returns one row per COMPANY ranked by how many roles they opened recently, with new departments and locations called out. Use Companies for sales and recruiting prospecting; use Jobs to find the roles themselves. Closed returns roles this index watched DISAPPEAR, with the day they went and how long they were open: a view no job board publishes, because it only exists if something looked yesterday too.

## `title` (type: `array`):

Words that must appear in the job title, one per line. Several lines are OR-ed. End a word with \* to match its prefix: engineer\* also matches engineering. Quotes are not needed and a multi-word line is matched as a phrase, so product manager finds "Product Manager" but not "Product Marketing Manager". MATCHING IS BY WORD STEM, which is what makes nurse find "Nursing Assistant" without you asking. The cost is that words sharing a stem also match: accountant returns "Account Executive" (90% of its hits on the current index), designer returns "Design Engineer" (47%). Measured 2026-08-18: engineer 0.3%, manager 8.5%, nurse 8.5%, analyst 0%. Add the distinguishing word, or use titleExclude, when a stem collides.

## `titleExactWords` (type: `boolean`):

Off by default. Titles are matched by word stem, so accountant also returns Account Executive and designer also returns Design Engineer. Turn this on to keep only titles that literally contain a word you typed. A term ending in \* is prefix matching you asked for, so it is honoured either way.

## `location` (type: `array`):

Places to match, one per line, e.g. berlin or united kingdom. Several lines are OR-ed. Matched against the location the employer published, so a country works when a city is not given. For remote work use Work arrangement instead, which uses what the board states rather than the word in the text.

## `countries` (type: `array`):

Only roles in these countries, matched on a country resolved from the employer's location string rather than on the text itself. Use it when you want German roles without caring whether the board wrote "Berlin, Germany", "Berlin", "Munich, DE" or "DE - Berlin". Say the country however you like: "Germany", "DE" and "Deutschland" all work, as do "US", "USA", "UK", "GB" and "Britain". Resolved on 87.8% of roles; the rest publish something no rule can read, like "EMEA" or a bare "Cambridge", and are excluded rather than guessed at. A country the index holds no roles in is named in the log instead of returning an empty dataset silently.

## `company` (type: `array`):

Company or board names to match, one per line. Several lines are OR-ed. Use \* for a prefix.

## `department` (type: `array`):

Departments or teams to match, one per line, e.g. engineering or design. Present on 44% of jobs, so this narrows results to those that publish it.

## `keywords` (type: `array`):

Search title, company, location and department together, one term per line. Use this when you do not care which field matched.

## `titleExclude` (type: `array`):

Drop roles whose title contains any of these, one per line, e.g. intern or sales. Excluded jobs are never returned and never charged.

## `companyExclude` (type: `array`):

Drop jobs from these companies, one per line. Useful for staffing agencies or companies you have already applied to.

## `locationExclude` (type: `array`):

Drop jobs in these places, one per line.

## `workArrangements` (type: `array`):

Remote, hybrid or on-site. Taken from what the board itself states wherever it does: Ashby and Oracle publish a workplace type, many Workday boards a remote type, and Workable, BambooHR and Breezy a remote flag. Where none says, it is read from the location text, and a job we could not classify is left out of all three rather than guessed into one.

## `seniority` (type: `array`):

Derived from the job title, because no ATS publishes a seniority field. About a third of jobs carry one; the rest state nothing recognisable in the title and are left unlabelled rather than guessed. Filtering here therefore narrows to jobs that say so in the title.

## `employmentTypes` (type: `array`):

Full-time, contract, part-time, temporary or internship. Taken from the board's own field on 42% of jobs; the rest do not publish one and are left unlabelled.

## `postedAfter` (type: `string`):

An ISO date, e.g. 2026-07-01. Jobs whose board publishes no posting date are excluded when this is set, because no date is not evidence of a recent one. BambooHR and Rippling publish no date on their listing endpoints at all, so their roles are never returned by a dated search.

## `changedSince` (type: `string`):

An ISO date, e.g. 2026-08-01. Returns only postings this index first SAW on or after that day, which is what you want when you are syncing into your own system: consecutive runs tile with no gap and no overlap. Different from Posted after, which uses the date the employer wrote and is absent entirely on BambooHR and Rippling. Jobs already open the first time we read their board have no first-seen date and are excluded, because we did not watch them appear.

## `withSalaryOnly` (type: `boolean`):

Keep only roles where the employer published a pay band. Three platforms publish one at all: Ashby as the band the employer wrote, Personio and Breezy as a structured minimum and maximum with a currency. Never parsed out of prose.

## `minAnnualSalary` (type: `integer`):

Only roles whose published lower bound is at least this, per year. Hourly and monthly bands are converted (2,080 hours or 12 months). Compared in the role's own currency, so pair it with Salary currency. Roles that publish no band are excluded, because an absent number is not evidence of a high one.

## `maxAnnualSalary` (type: `integer`):

Only roles whose published lower bound is at most this, per year. Same conversion and same currency caveat as the minimum.

## `salaryCurrency` (type: `array`):

Restrict to bands published in these currencies. Nothing is converted between them: 88% of published bands are US dollars, and baking today's exchange rate into an index rebuilt every night would go stale by morning.

## `maxResults` (type: `integer`):

A hard ceiling on jobs returned and charged. Defaults to 1,000 if you leave it out, and is capped at 10,000 for one search, so a broad query can never produce a surprise bill. Set it to 0 for a dry run that returns and charges nothing.

## `hiringLabels` (type: `array`):

Surging is the top 1% of companies by roles opened in 30 days, growing the top 10%, steady everything else that is hiring, quiet nothing new. The cut points are percentiles of the live data, not fixed numbers, so they keep their meaning as the index grows.

## `minOpenedLast30` (type: `integer`):

Only companies that opened at least this many roles in the last 30 days.

## `minOpenedLast7` (type: `integer`):

Only companies that opened at least this many roles in the last 7 days. The sharpest signal that something changed at that company this week.

## `minOpenRoles` (type: `integer`):

Filters out companies with only a handful of postings.

## `enteringNewDepartments` (type: `boolean`):

Only companies whose recent postings are in a department they were not hiring for before. A company opening its first sales or security roles is a company that just changed strategy, which is the strongest buying signal in the dataset.

## `withContactOnly` (type: `boolean`):

Only companies whose own website publishes a way to reach them: a role address like info@ or sales@, a phone number from a tel: link, or the company's own social profiles. Nothing is guessed and no personal address of a named individual is ever collected. Companies not yet crawled are excluded rather than counted as having none.

## `includeStaffingAgencies` (type: `boolean`):

Staffing agencies and recruiters post enormous volumes on behalf of other companies and dominate any hiring ranking, so they are excluded by default in Companies mode. 126 companies (2.7% of jobs) are flagged, conservatively and by name, and every row carries looksLikeAgency so you can judge for yourself. Jobs mode never hides them.

## Actor input object example

```json
{
  "mode": "jobs",
  "title": [
    "engineer"
  ],
  "titleExactWords": false,
  "withSalaryOnly": false,
  "maxResults": 200,
  "enteringNewDepartments": false,
  "withContactOnly": false,
  "includeStaffingAgencies": false
}
```

# Actor output Schema

## `results` (type: `string`):

Every row this search returned, as JSON.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "title": [
        "engineer"
    ],
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("glitchbound/adp-jobs-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "title": ["engineer"],
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("glitchbound/adp-jobs-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "title": [
    "engineer"
  ],
  "maxResults": 200
}' |
apify call glitchbound/adp-jobs-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,glitchbound/adp-jobs-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rXq5uKbzn7s707VFB/builds/TJLQsdKgbJxtF1wqs/openapi.json
