Onetonline APIonetonline.org ↗
Search O*NET-SOC occupations by keyword and retrieve live job openings by state or ZIP code. Returns occupation codes, titles, employers, and posting dates.
What is the Onetonline API?
The O*NET OnLine API exposes 2 endpoints that cover occupation search and live job listing retrieval against the O*NET-SOC taxonomy. The search_occupations endpoint returns every matching occupation—often several hundred rows—with O*NET-SOC codes, titles, and Bright Outlook flags. The list_job_openings endpoint then maps any occupation code to current postings, filtered nationwide, by US state, or by ZIP code proximity.
curl -X GET 'https://api.parse.bot/scraper/36a445fb-2f68-4b94-a5ee-583473dc4d93/search_occupations?query=dental+assistant' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace onetonline-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: O*NET OnLine Job Openings API — search occupations, then browse openings."""
from parse_apis.onetonline_org_api import OnetOnline, State, OccupationNotFound
client = OnetOnline()
# Search for occupations matching a keyword; cap total items fetched.
for occ in client.occupations.search(query="dental assistant", limit=5):
print(occ.title, occ.occupation_code, occ.bright_outlook)
# Drill into the first matching occupation's job openings in one state.
occ = client.occupations.search(query="software developer", limit=1).first()
if occ is not None:
print(f"\nJob openings for {occ.title} in New York:")
for job in occ.job_openings.list(state=State.NY, limit=3):
print(f" {job.title} at {job.company} — {job.location} ({job.posted_date})")
# Point-construct an occupation by its known code and list nationwide openings.
try:
nurse = client.occupation(occupation_code="29-1141.00")
for job in nurse.job_openings.list(limit=5):
print(job.title, job.company, job.location)
except OccupationNotFound as e:
print(f"Occupation not found: {e.occupation_code}")
print("\nexercised: occupations.search / occupation() / job_openings.list")
Searches O*NET OnLine occupations by keyword or O*NET-SOC code and returns every matching occupation in the site's relevance order (a single page; the site returns the full match list in one response, often several hundred rows). Each row carries the O*NET-SOC occupation_code that list_job_openings accepts, the occupation title, whether the site flags it as Bright Outlook, and the occupation summary page URL. A query with no matches returns an empty occupations array with total 0.
| Param | Type | Description |
|---|---|---|
| queryrequired | string | Keyword, job title, or O*NET-SOC code to search for (e.g. dental assistant). |
{
"type": "object",
"fields": {
"query": "the search term as submitted",
"total": "integer count of occupations returned",
"occupations": "array of matching occupations, each with occupation_code (O*NET-SOC code string, e.g. 31-9091.00), title, bright_outlook (boolean), occupation_url"
},
"sample": {
"data": {
"query": "dental assistant",
"total": 594,
"occupations": [
{
"title": "Dental Assistants",
"bright_outlook": true,
"occupation_url": "https://www.onetonline.org/link/summary/31-9091.00",
"occupation_code": "31-9091.00"
},
{
"title": "Dental Laboratory Technicians",
"bright_outlook": false,
"occupation_url": "https://www.onetonline.org/link/summary/51-9081.00",
"occupation_code": "51-9081.00"
}
]
},
"status": "success"
}
}About the Onetonline API
Occupation Search
The search_occupations endpoint accepts a query parameter—a keyword, job title fragment, or an O*NET-SOC code like 31-9091.00—and returns a single-page result set containing every matching occupation in relevance order. Each occupation in the occupations array carries an occupation_code (the canonical O*NET-SOC string), a human-readable title, and a bright_outlook boolean that flags occupations projected to grow significantly or have large numbers of openings. The total field gives the integer count of matches for that query.
Job Openings by Occupation
The list_job_openings endpoint accepts an occupation_code from the search results and returns current job postings associated with that occupation. Each entry in the jobs array includes title, company, location (City, ST format), posted_date (e.g. September 18, 2026), and job_url linking directly to the posting's detail page. Results paginate via a 1-based page parameter; the has_more boolean indicates whether another page exists, and total reports the full count the source shows for the selected scope.
Geographic Filtering
Job openings can be scoped in three ways: omit both state and zip_code for nationwide results, pass a two-letter state code (e.g. CA, TX, PR) to restrict to that state or territory, or supply a 5-digit zip_code to retrieve openings near that location. The state and zip_code parameters are mutually exclusive. The area field in the response reflects the scope the site applied—nationwide, in <State>, or near <ZIP>—and is null when no openings were found for the combination.
The Onetonline API is a managed, monitored endpoint for onetonline.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when onetonline.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official onetonline.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build an occupation explorer that maps keywords to O*NET-SOC codes and displays projected demand using the
bright_outlookflag. - Aggregate job postings by occupation code and state to visualize regional hiring demand across the US.
- Power a career-guidance tool that takes a user's job title query and surfaces live openings tied to the closest matching O*NET occupation.
- Monitor hiring trends for a set of occupation codes by polling
list_job_openingsperiodically and tracking changes intotal. - Provide ZIP-code-aware job recommendations by chaining
search_occupationswithlist_job_openingsusing thezip_codefilter. - Enrich workforce analytics dashboards with standardized O*NET-SOC codes and employer names from posting data.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does O*NET OnLine have an official developer API?+
What does `list_job_openings` actually return, and how do I page through results?+
jobs array of postings for the given occupation_code, each with title, company, location, posted_date, and job_url. The total field shows how many openings exist for the selected scope. Pass an incrementing page integer (1-based) to retrieve subsequent pages. When has_more is false, you have reached the last page. Passing a page number beyond the last returns an empty jobs array.Can I combine `state` and `zip_code` in the same request?+
state for a statewide filter or zip_code for proximity-based results. Omit both to get nationwide openings. The area field in the response confirms which scope was applied.Does the API return occupation details such as skills, tasks, wages, or education requirements?+
occupation_code, title, and bright_outlook) and job posting listings. Detailed occupational attributes—skills, tasks, knowledge areas, median wages—are not included in the response fields. You can fork this API on Parse and revise it to add an endpoint pulling those details.How fresh are the job postings returned by `list_job_openings`?+
posted_date string exactly as the source displays it (e.g. September 18, 2026), so you can assess recency per listing. The API reflects what the O*NET OnLine site shows at the time of the request; postings that have been removed from the site will not appear in results.