Job Search Node
The Job Search Node pulls job postings straight from company ATS boards —
Greenhouse, Lever,
Ashby and Workable — for a
list of companies you choose. No API key. Every returned job carries a direct
applyUrl to the employer's own application form.
These ATS APIs are per-company, not searchable. The node only sees the companies you list (plus an optional built-in starter set) — a great role at a company you didn't list is invisible. In exchange you get real, direct apply links and no rate caps.
Configuration
- Companies
- Search
- Filters
- Work Eligibility
- Limits
- Upstream Input
- Configuration Schema
One company per line. Any of:
greenhouse:stripe— explicit ATS + board tokenlever:vercel,ashby:linear,workable:acme- the company's ATS-hosted board URL —
https://jobs.ashbyhq.com/ramp,https://boards.greenhouse.io/stripe,https://jobs.lever.co/vercel. This is not the company's own careers page (acme.com/careers) — those are custom pages the parser can't read; open a job listing from them and copy the ATS domain it lands on instead. - a bare name —
Some Company— auto-located across the four ATSs (only works if the slugified name matches the real board token)
Built-in companies is a searchable multiselect over a vendored ~138-company starter set (Greenhouse / Lever / Ashby) — pick individual companies, or use Select all, Clear, or + All greenhouse/lever/ashby/workable to select in bulk. Selected companies run alongside whatever you typed in the box above.
Workable's public endpoint is heavily rate-limited — a throttled company just
shows up in errors[] and the run continues.
- Keywords: a comma-separated list of phrases, matched
case-insensitively against the job title and department only (not the
description). A role matches a phrase when every word of that phrase
appears in the title (any order; substring, so
engineeralso hitsengineering;-//are ignored). A role matches if any phrase matches. Shorter phrases match more broadly —full stackcatches every full-stack role,full stack engineeronly those with all three words,senior full stack engineerfewer still. No synonym expansion: to span engineer/developer, list both or use a shorter stem. Empty = every role at the listed companies. - Remote only: keep only roles the ATS flags as remote.
- Employment type: full-time / part-time / contract / internship (empty = any).
- Posted: only roles newer than the chosen window.
- Seniority: best-effort, inferred from the title.
- Candidate region: where you'd work from. Each job is tagged with
eligibleFromTarget(true/false/null) andeligibilityConfidence. ATS location data is free text, so confidence is usuallylow. - Drop jobs that clearly exclude this region: removes only high-confidence mismatches. Weak signal here — most jobs pass.
- Max companies per run: fan-out safety cap (default 60). Company responses are cached ~30 min, so re-runs while tuning filters are near-instant.
- Max results: cap on returned jobs after filtering.
Enable Provided by Upstream to take companies / keywords /
candidateRegion from an upstream node's payload — e.g. an LLM node that
expands "fintech companies hiring remotely" into a list of slugs.
This is the full JSON Schema for the node's data configuration object, generated from the Zod schema used to validate the node at runtime.
{
"type": "object",
"properties": {
"companies": {
"type": "string",
"description": "Companies to pull, one per line: `greenhouse:stripe`, `lever:vercel`, `ashby:linear`, `workable:acme`, the company's ATS-hosted board URL (jobs.ashbyhq.com/…, boards.greenhouse.io/…, jobs.lever.co/…, apply.workable.com/… — NOT the company's own careers page, which can't be parsed), or a bare name (auto-located across the four ATSs)."
},
"seedCompanies": {
"type": "array",
"items": {
"type": "string"
},
"description": "`ats:token` keys selected from the built-in starter company list (Greenhouse/Lever/Ashby)."
},
"keywords": {
"type": "string",
"description": "Comma-separated phrases matched against the job title/department (case-insensitive). A role matches a phrase when EVERY word of the phrase appears in the title (any order, substring, so 'engineer' also hits 'engineering'). A role matches if ANY phrase matches. Shorter phrases match more broadly. Empty = every role at the listed companies."
},
"remoteOnly": {
"type": "boolean",
"description": "Keep only roles the ATS flags as remote."
},
"employmentTypes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"full_time",
"part_time",
"contract",
"internship"
]
},
"description": "Employment types to include. Empty = any."
},
"datePosted": {
"type": "string",
"enum": [
"any",
"today",
"3days",
"week",
"month"
],
"description": "Only return roles posted within this window."
},
"seniority": {
"type": "string",
"enum": [
"any",
"junior",
"mid",
"senior",
"lead"
],
"description": "Seniority filter (best-effort, from title)."
},
"candidateRegion": {
"type": "string",
"description": "Where you would work from, e.g. 'Cyprus', 'Europe'. Tags each job's eligibility from its location text (best-effort — ATS location data is free text)."
},
"filterByEligibility": {
"type": "boolean",
"description": "Drop roles whose location is a concrete place that doesn't match candidateRegion (e.g. 'Engineer - Germany' when you set 'Cyprus'). Roles with vague/unspecified locations are kept."
},
"maxCompanies": {
"type": "integer",
"minimum": 1,
"maximum": 400,
"description": "Cap on how many companies to query in one run (fan-out safety)."
},
"resultsLimit": {
"type": "integer",
"minimum": 1,
"maximum": 500,
"description": "Cap on returned jobs after filtering."
},
"dataProvidedByUpstream": {
"type": "boolean",
"description": "Take `companies` / `keywords` / `candidateRegion` from the upstream node's payload instead of the fields above."
}
},
"required": [
"companies",
"seedCompanies",
"keywords",
"remoteOnly",
"employmentTypes",
"datePosted",
"seniority",
"candidateRegion",
"filterByEligibility",
"maxCompanies",
"resultsLimit",
"dataProvidedByUpstream"
],
"additionalProperties": false
}
Output
{
"jobs": [
{
"source": "ashby", "ats": "ashby",
"title": "Senior Backend Engineer",
"company": "linear", "companyToken": "linear",
"department": "Engineering",
"url": "https://jobs.ashbyhq.com/linear/…",
"applyUrl": "https://jobs.ashbyhq.com/linear/…/application", // direct employer form
"location": "North America", "isRemote": true,
"candidateLocations": ["North America"],
"eligibleFromTarget": null, "eligibilityConfidence": "low",
"employmentType": "Full-time",
"postedAt": "2026-08-14T20:34:59.324Z",
"descriptionText": "…plain text, for an LLM…"
}
],
"counts": { "companies": 60, "reachable": 60, "jobsFetched": 5104, "afterFilter": 246, "afterDedupe": 237, "returned": 15 },
"errors": [ { "company": "acme", "ats": "workable", "message": "Workable (acme) returned 429 Too Many Requests" } ]
}
Common Use Cases
- Targeted job hunt: list your 30–80 dream companies, filter for remote senior roles, get direct apply links.
- LLM screening: feed
jobsto an AI Data Processing node to rank fit or draft cover letters —descriptionTextis included. - Daily digest: pair with a Timer Node and a Slack Output node.
Best Practices
- Curate the Companies list — that's the real lever. The built-in set is a starting point, not a market.
- Keep Max companies modest; the cache makes iterative filtering cheap.
- Use specific multi-word keywords; matching is title/department only.
Troubleshooting
- A company in
errors[]: wrong token, company not on that ATS, or (Workable) rate-limited. Check the careers-page URL for the real slug. reachable<companies: some tokens didn't resolve — seeerrors[].- Few results: broaden keywords, widen Posted, turn off Remote only, or raise Max companies.
- Missing Workday/Taleo companies: not supported — their public APIs need per-tenant auth, and they gate applications behind mandatory accounts anyway.