Eightfold Jobs API: Get Eightfold Job Listings as JSON
TL;DR
Eightfold career sites, on {company}.eightfold.ai or a vanity host, load jobs from a public JSON endpoint at /api/apply/v2/jobs that needs no key, cookie or token. The list pages with start at a fixed 10 jobs per page whatever num says, and its job_description is often missing, so you fetch /api/apply/v2/jobs/{id} for the full HTML description. Use t_create (epoch seconds) as the post date rather than t_update, and expect some tenants to refuse the v2 list with a 403 and serve jobs through /api/pcsx/search instead.
On this page
To get a company's jobs from Eightfold, page through https://{host}/api/apply/v2/jobs?start=0&num=10, then call https://{host}/api/apply/v2/jobs/{id} for each job's full description. Both are public JSON endpoints with no API key, cookie or CSRF token, and they're the same calls the Eightfold career site makes in your browser. The catch is volume: the list is fixed at 10 jobs per page, and large enterprise tenants have thousands of jobs.
That's the DIY route, and it works for a handful of companies you already know. If you'd rather not build and maintain an Eightfold scraper, CleanJobData already ingests ATS platforms and company career sites and serves the jobs normalized through one REST API — see the Jobs API docs.
At a Glance
| List endpoint | GET https://{host}/api/apply/v2/jobs?start={n}&num=10 |
| Detail endpoint | GET https://{host}/api/apply/v2/jobs/{id} |
| API key | None |
| Pagination | Offset (start), fixed 10 per page |
| Full description | Unreliable in the list; always in the detail |
| Post date | t_create, epoch seconds |
| Salary field | No |
| Remote | work_location_option on the list |
What Eightfold Is
Eightfold AI sells a talent intelligence platform to large enterprises: banks, insurers, mining and industrial companies, defense contractors and retailers. Many customers use Eightfold's career site on top of a separate applicant tracking system, so Eightfold is often what candidates see even though the requisition lives elsewhere.
Eightfold also has APIs for its customers, which need credentials issued for the employer's account. The career-site endpoints below are different: they serve published jobs to anyone, and the robots.txt on the tenants we checked explicitly allows /api/apply.
Finding the Host
Eightfold career sites live at https://{company}.eightfold.ai/careers. Some employers put a vanity host in front, such as careers.acme.com, and the same API answers there. The host is all you need.
The list endpoint accepts an optional domain query parameter, and the career site sends one. Leave it out. The API works without it and returns the same jobs, while a wrong domain on a real tenant returns an HTML 404 that looks exactly like a missing board.
Listing Jobs
curl "https://acme.eightfold.ai/api/apply/v2/jobs?start=0&num=10"The response is an envelope with a total count and a positions array, plus many keys that only matter to the career site's UI. A trimmed row (values illustrative):
{
"count": 1590,
"positions": [
{
"id": 43831466,
"name": "Maintenance Technician",
"location": "Belo Horizonte, Minas Gerais, Brazil",
"locations": ["Belo Horizonte, Minas Gerais, Brazil"],
"department": "Operations",
"business_unit": "Base Metals",
"t_create": 1786766641,
"t_update": 1790165158,
"ats_job_id": "5369",
"display_job_id": "5369",
"job_description": "Join our maintenance team...",
"work_location_option": "onsite",
"canonicalPositionUrl": "https://acme.eightfold.ai/careers/job/43831466"
}
]
}Pagination
The page size is a hard 10. We tried num values from 11 to 1,000, and other names such as limit, page_size, per_page and size. Every request still returned 10 jobs. Advance start by 10 until you've covered count.
You can't ask for newest jobs only, either. sort_by is silently ignored with any value, and the default order is only loosely newest-first. So every sync has to page the whole list: a 1,590-job tenant is 159 requests before you fetch a single description. Jobs open and close while you page, so the list can shift by a few rows. Dedupe by id, and accept a small gap against count rather than retrying forever.
Fetching the Detail
curl "https://acme.eightfold.ai/api/apply/v2/jobs/43831466"The detail has the same core fields as the list row, and its job_description is the full HTML description. You need it because the list's job_description is unreliable: in our samples it was present on 37 of 40 rows on one tenant, 6 of 40 on another and 0 of 21 on a third, and when present it can be cut short.
work_location_option is the exception: it's on the list row, and the detail returns null for it. Keep the list row and merge it with the detail.
Fetching Eightfold Jobs (Python)
import time
from datetime import datetime, timezone
import requests
HEADERS = {"accept": "application/json"}
def get_json(url, params=None):
res = requests.get(url, params=params, headers=HEADERS, timeout=30)
res.raise_for_status()
return res.json()
def list_eightfold_jobs(host):
rows, start, total = {}, 0, None
while total is None or start < total:
data = get_json(f"https://{host}/api/apply/v2/jobs", {"start": start, "num": 10})
total = data["count"]
page = data.get("positions") or []
if not page:
break
for row in page:
rows.setdefault(row["id"], row) # the list can shift while you page
start += 10 # fixed page size, whatever num says
time.sleep(0.3)
return list(rows.values())
def fetch_job(host, row):
detail = get_json(f"https://{host}/api/apply/v2/jobs/{row['id']}")
return {
"id": str(row["id"]),
"title": row["name"].strip(),
"posted_at": datetime.fromtimestamp(row["t_create"], tz=timezone.utc),
"locations": detail.get("locations") or row.get("locations") or [],
"workplace": row.get("work_location_option"), # list only
"description_html": detail.get("job_description") or row.get("job_description") or "",
"url": row.get("canonicalPositionUrl") or f"https://{host}/careers/job/{row['id']}",
}
rows = list_eightfold_jobs("acme.eightfold.ai")
jobs = [fetch_job("acme.eightfold.ai", r) for r in rows[:20]]t_create is in the list, so you can drop jobs older than your cutoff before making any detail calls.
Fields Worth Knowing
idis numeric and stable. Use it as the dedup key.nameis the job title.t_createis the creation time in epoch seconds. It looked like a real creation date on every tenant we checked: spread over weeks to months, at working-hours times, never in the future.t_updateis not a post date. On one tenant, 966 of 1,590 jobs had at_updatein the same hour, which points to a bulk refresh. The career page's JSON-LDdatePostedalso moves between the two values and carries no time zone, sot_createis the field to trust.locationsis an array of free-text strings, andlocationis the first one. There are no separate city, state or country fields, and the format varies by tenant ("Brazil", "Melbourne, FL, US", "United States-Florida-Melbourne"). The location normalization guide covers resolving them.work_location_optionisonsite,hybrid,remoteorremote_local.remote_localreads as remote limited to a region, but we haven't confirmed what the career site shows for it.canonicalPositionUrlis the candidate-facing job page, on the vanity host when the tenant has one.department,business_unit,ats_job_idanddisplay_job_idare present on many tenants. The last two carry the employer's own requisition number.- No salary, no employment type and no reliable company name or website. Pay, when published, is in the description text.
PCSX Tenants
Some tenants answer the v2 list with a 403 and a JSON body of {"message": "Not authorized for PCSX"}. That doesn't mean the board is gone. These tenants serve their list through a second search API:
curl "https://acme.eightfold.ai/api/pcsx/search?domain=acme.com&start=0&num=10"This one does need domain, set to the employer's own domain (acme.com, not the Eightfold host). The response is wrapped as {"status": 200, "error": ..., "data": {"count": ..., "positions": [...]}}, and the rows use camelCase names: creationTs instead of t_create, workLocationOption instead of work_location_option, positionUrl as a relative path, and an extra standardizedLocations array. Page it the same way, 10 at a time. The v2 detail endpoint still works on these tenants, so everything after the list is the same.
Gotchas
There's no clean "board removed" signal. A tenant that no longer exists fails at DNS with no HTTP status, and a mistyped host gives an HTML 404. Neither is a reliable reason to delete a company's jobs; investigate before you expire anything.
401, 403 and 404 on the list are usually not about the board. They mean a PCSX tenant, a wrong domain, or a change on Eightfold's side.
Volume adds up. A big tenant is hundreds of list pages plus one detail call per new job. Keep concurrency low, pause between batches, and back off on 429 and 5xx.
Reposts keep their ID. If an employer reposts a job, the id and t_create can stay the same, so the job won't look new.
No webhooks. Poll the list, diff the IDs against your last complete run, and only expire jobs when the full list came back. See syncing job data in depth.
When This Is Enough
For one employer, these endpoints are clean JSON with no authentication, and the code above is most of what you need.
When It Isn't
Across many Eightfold tenants, the fixed page size makes every sync expensive, locations stay free text, and PCSX tenants need their own code path. Eightfold is also one platform among many; the ATS public job postings API list compares 33, and Workday is the other big enterprise platform with an offset-paged JSON list and a detail call per job.
Skip the scraper: get this data from the CleanJobData API
If you'd rather not maintain an Eightfold collector, you can query normalized jobs from ATS platforms and company career sites with a single request. The response has structured city/state/country locations, parsed salary when the employer publishes one, a remote type, and company metadata, and you page through results with the cursor in pagination.next_page.
curl "https://api.cleanjobdata.com/jobs?title=engineer&company_website_url=acme.com&limit=20" \
-H "Authorization: Bearer $CLEANJOBDATA_API_KEY"Eightfold jobs come back in the same schema as every other source, with their free-text locations resolved to cities, states and countries. Use company_website_url or employer_id to scope to one employer. Coverage depends on which employers are in the dataset, so check that the companies you care about appear before you rely on it.
- Jobs API reference for every filter and response field
- Playground to run queries without writing code
- Pricing — the Trial is free with no card required
FAQ
Does Eightfold have a public jobs API?
Yes, though it's undocumented. Every Eightfold career site calls GET https://{host}/api/apply/v2/jobs for the list and /api/apply/v2/jobs/{id} for each job, with no key, cookie or token.
Why does Eightfold only return 10 jobs per page?
The page size is fixed at 10 on the server. Larger num values and other page-size parameters are ignored, so you advance start by 10 until you reach count.
Which Eightfold date field is the posting date?
Use t_create, which is epoch seconds. t_update changes when Eightfold refreshes jobs in bulk, so many jobs share the same value.
What does "Not authorized for PCSX" mean?
The tenant serves its job list through Eightfold's PCSX search API instead of the v2 list. Call /api/pcsx/search with the employer's own domain in the domain parameter; the v2 detail endpoint still works for each job.