Ashbyhq APIashbyhq.com ↗
Search and retrieve job postings from any Ashby-powered job board. Filter by title, department, and experience level. 3 endpoints, structured JSON output.
What is the Ashbyhq API?
The Ashby HQ API gives developers structured access to job listings across Ashby-powered company job boards through 3 endpoints. The search_jobs endpoint supports filtering by title keywords, department name, and min/max years of experience — including automatic extraction of experience requirements from job descriptions. You can retrieve full job details by ID or enumerate all departments and teams with their posting counts.
curl -X GET 'https://api.parse.bot/scraper/b2f8b925-5ff9-47c8-8771-18f96c070747/search_jobs?location=Canada&organization=ashby' \ -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 ashbyhq-com-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: Ashby Job Board SDK — search jobs, explore departments, get details."""
from parse_apis.ashby_job_board_api import AshbyJobs, Organization, ResourceNotFound
client = AshbyJobs()
# List departments to understand board structure
for dept in client.departments.list(organization=Organization.ASHBY, limit=5):
print(dept.department, dept.job_count, [t.name for t in dept.teams])
# Search jobs filtered by department
job_summary = client.jobsummaries.search(department="Engineering", limit=1).first()
if job_summary:
print(job_summary.title, job_summary.location, job_summary.is_remote)
# Drill into full details (includes HTML description)
full_job = job_summary.details()
print(full_job.title, full_job.employment_type, full_job.description_html[:100])
# Typed error handling for a bad organization
try:
for j in client.jobsummaries.search(organization="nonexistent_org_xyz", limit=1):
print(j.title)
except ResourceNotFound as exc:
print(f"Organization not found: {exc}")
print("exercised: departments.list / jobsummaries.search / job_summary.details / ResourceNotFound")
Search job postings with optional filters for title keywords, department, and experience range. Extracts experience requirements from job descriptions. Returns all jobs when no filters are specified. Returns stale_input with kind 'input_not_found' if the organization slug does not exist.
| Param | Type | Description |
|---|---|---|
| department | string | Department name to filter by (partial match, case-insensitive) |
| organization | string | Organization slug on Ashby job board (e.g. 'ashby', 'openai') |
| max_experience | integer | Maximum years of experience to filter by (jobs without stated experience are included) |
| min_experience | integer | Minimum years of experience to filter by (jobs without stated experience are included) |
| title_keywords | string | Comma-separated title keywords to filter by (e.g. 'Engineer,Designer,Sales') |
{
"type": "object",
"fields": {
"jobs": "array of job objects with id, title, department, team, employment_type, location, secondary_locations, is_remote, workplace_type, published_at, job_url, apply_url, experience_requirements, years_of_experience, consulting_experience_mentioned, description_plain",
"matching_jobs": "integer number of jobs matching the applied filters",
"total_jobs_on_board": "integer total number of jobs on the board"
},
"sample": {
"data": {
"jobs": [
{
"id": "7458d4e9-da2e-47bd-98cb-adfda43d42b2",
"team": "EMEA Engineering",
"title": "Engineering Manager, EU",
"job_url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2",
"location": "Remote - European Union",
"apply_url": "https://jobs.ashbyhq.com/ashby/7458d4e9-da2e-47bd-98cb-adfda43d42b2/application",
"is_remote": true,
"department": "Engineering",
"published_at": "2024-03-04T14:29:08.532+00:00",
"workplace_type": "Remote",
"employment_type": "FullTime",
"description_plain": "Hi, I'm Colin, Director of Engineering...",
"secondary_locations": [
"Romania",
"Switzerland",
"Spain"
],
"years_of_experience": [],
"experience_requirements": "",
"consulting_experience_mentioned": false
}
],
"matching_jobs": 59,
"total_jobs_on_board": 59
},
"status": "success"
}
}About the Ashbyhq API
Searching Jobs
The search_jobs endpoint accepts an organization slug (e.g. openai, ashby) to target a specific company's board. Optional filters include title_keywords (comma-separated, e.g. BizOps,Strategy), department (partial match, case-insensitive), and min_experience / max_experience integers in years. The response includes a jobs array — each entry carries id, title, department, team, employment_type, location, secondary_locations, is_remote, and workplace_type — along with matching_jobs and total_jobs_on_board counts. Jobs without a stated experience requirement are included regardless of experience filters. If the organization slug does not exist, the endpoint returns a stale_input result with kind input_not_found.
Job Details
get_job_details takes a job_id UUID (obtained from search_jobs results) and an optional organization slug. It returns a job object with the same structural fields as the search response, plus the full HTML job description and an experience level analysis derived from the posting content. The same stale_input / input_not_found behavior applies if either the job ID or organization slug is invalid.
Departments and Teams
list_departments returns every department on a given organization's board, each with a department name string, a job_count integer, and a nested teams array. Each team object includes the team name and its own job count. The endpoint also surfaces a total_jobs integer for the entire board. This is useful for building navigation or discovering which departments are actively hiring before issuing targeted search_jobs calls.
The Ashbyhq API is a managed, monitored endpoint for ashbyhq.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when ashbyhq.com 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 ashbyhq.com 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?+
- Aggregate open roles across multiple Ashby-powered company boards into a single job feed
- Filter engineering or data science postings by experience range using min_experience and max_experience
- Build a department-level hiring dashboard using job_count data from list_departments
- Monitor a specific company's total_jobs_on_board count over time to track hiring velocity
- Extract structured team hierarchy from the teams array within each department object
- Match candidates to postings by comparing extracted experience requirements from job descriptions
- Populate role-detail pages with HTML job descriptions and location data from get_job_details
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.