Get everything known about one job
const url = 'http://127.0.0.1:8765/api/jobs?url=example';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'http://127.0.0.1:8765/api/jobs?url=example'One job, complete: posting, rank, assessment + requirement matrix, open questions, tailored resumes, job state, action links. 0.1.11.9 (one job, one assessment): the job has ONE stored assessment, resume and suggestion record. job_state, rank and open_questions are the job’s (from that one assessment; the run’s own only while nothing is stored), and no link carries a profile_id: links.pick, brief and suggestions act on the job. A role (a profile) is a TAG: tags lists the active roles whose saved search found the job, best first, each with its own rank_score ([{profile_id, label, match_rank, rank_score}]; empty for a job no role found). ambiguous_applied_resume is null, or {resumes, text} for a job the stores migration found applied with a stored resume under more than one role: the PDF that was sent cannot be told and every one of those resumes is kept. Never calls a model. 0.1.11.4: liveness says whether the posting’s board still lists it: state is open | closed | unknown, checked_at when the board was asked, closed_at since when it is closed, note one plain sentence for a closed one (null otherwise). That is ONE request to the posting’s public board at most (Greenhouse: its single-job endpoint, 404 or 410 is closed; Lever and Ashby: the board’s list, closed only when a list that answered 200 no longer has the posting), none within an hour of the last answer and none for a posting already removed; anything else the board says (5xx, 429, a redirect, a timeout) is unknown and changes nothing. A closed posting of the index gets removed_at (GET /api/postings then lists it only with removed=1); a job that is no index posting is only reported. liveness.board_url is the posting’s address on its board, built from the index’s board token and posting id (Greenhouse https://job-boards.greenhouse.io/<token>/jobs/<id>, Lever https://jobs.lever.co/<token>/<id>, Ashby https://jobs.ashbyhq.com/<token>/<id>), when the stored URL is the company’s own page (any host that is not the board’s) and the posting is not closed; null otherwise, and always null for a job with no index posting. For such a posting whose board answered open, this read (and no other route, never a batch) makes ONE more request, a GET of the stored URL, at most once an hour per job: liveness.company_page is down (404 or 410) | ok (2xx) | unknown (anything else: 5xx, 429, a redirect, a timeout; not asked; the check is off), and liveness.company_page_note is “The company page for this job is down; the job is still open on the board” when it is down (null otherwise). A company page that is down never closes or removes the posting: state stays open and removed_at stays null. Aggregates the newest run posting, its rank, every run or quick assessment of the job (with the requirement matrix), the questions still unanswered, stored tailored resumes, the job’s state with the events it accepts next, and the action links. The UI route #/jobs/<posting url> maps to this route. A job no run acquired is joined to its index posting by the URL alone, whatever host it is on (a Greenhouse board embedded in a company’s own site: https://www.<company>/jobs?gh_jid=<id>): posting then has the index’s location, work_mode, salary, provider and board_token, rank is {normalized_url, score, profile_id, source: "posting_index"} (the stored score; a run’s rank line has reasons and blockers instead), work_mode_fit and h1b are a run row’s, and index_posting is the GET /api/postings row for the job (null when the index does not hold it). For a posting the index holds, posting carries its dates as that row does: published_at (the day it went up; null when the board gives none), published_kind (posted | updated), updated_at (the board’s last change, null when it gives none) and first_seen_at (when Scout first stored it). In every response company is the company’s NAME (the company index’s, e.g. “Osprey Lane”); company_slug is the board token (“ospreylabs”: an id, never a name; null for a posting read from a page or pasted text) and company_name repeats the name. A matrix row’s class says what it weighs: hard and askable are must-haves (an open question on one holds the job at pending_user_answers), list_item is one tool of a list a single sentence names (“Docker, Helm, and Kubernetes”: its question is still asked, and one of them open does not hold a match), nice_to_have is a bonus. So a matched_above_threshold assessment can carry one question. minor_gaps names the list_item and nice_to_have rows that are not met and minor_gap_text says them in one line (“1 minor gap: Helm”). The matrix has a row for every requirement the posting states, must-haves first; past 40 rows rows_not_shown counts the rest. Each source: "quick" assessment carries basis_stale (and basis_stale_reason when true). job_state may carry assessment_stale: {reason: "posting_changed"} (absent otherwise) when the assessment that gives the state was made on posting text that has since changed: the verdict still reads, and the job should be re-assessed. The same marker carries reason older_prompt, settings_changed or story_bank_changed when the state comes from a stored quick assessment made with an older assess prompt, other candidate settings (work mode, countries, location, sponsorship need) or answers and stories that have since changed, and resume_changed when a master resume is stored and a resume line the assessment quoted is gone or a new line names one of its open questions; nothing is re-assessed until you ask (POST /api/assess, or assess-all). job_state.state weak_fit is needs_answers for a job whose stored assessment has few requirements met AND whose rank score is low (the fit block of the project’s settings: below 40% and below rank 50): it is not counted with the jobs that need your answers. job_state.state thin_posting (0.1.11.2) is matched for a job whose stored assessment has no requirement row about the job (an empty matrix, a lone “No stated requirements” row, eligibility rows alone): nothing was judged, so it is never shown or counted as a match. A matched verdict whose stored gate decision is not_a_match reads not_a_match.
Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The posting URL, raw or normalized (the UI’s #/jobs/<url> route maps here).
Responses
Section titled “Responses”Success.
object
Example
{ "ambiguous_applied_resume": null, "answers": [], "application_events": [], "assessments": [ { "matrix": [ { "class": "list_item", "requirement": "Helm", "resume_evidence": [], "status": "unclear" } ], "minor_gap_text": "1 minor gap: Helm", "minor_gaps": [ "Helm" ], "profile_id": null, "questions": [], "rows_not_shown": 0, "run_id": "run_20260929T100000Z", "source": "run", "suggestions": [], "verdict": "matched_above_threshold" } ], "h1b": null, "index_posting": null, "job_identity": "https://boards.greenhouse.io/acme/jobs/101", "job_state": { "next_events": [ "applied" ], "since": "2026-09-29T10:05:00Z", "state": "tailored" }, "links": { "assess": { "body": { "job": { "job_url": "https://boards.greenhouse.io/acme/jobs/101" } }, "method": "POST", "path": "/api/assess" }, "brief": { "method": "GET", "path": "/api/jobs/brief?url=...&part=yours" }, "brief_posting": { "method": "GET", "path": "/api/jobs/brief?url=...&part=posting" }, "mark_applied": { "body": { "event_kind": "applied", "normalized_url": "https://boards.greenhouse.io/acme/jobs/101" }, "method": "POST", "path": "/api/applications" }, "pdf": { "body": { "job_identity": "https://boards.greenhouse.io/acme/jobs/101" }, "method": "POST", "path": "/api/tailored-resumes/pdf" }, "pick": { "body": { "action": "refresh", "job_url": "https://boards.greenhouse.io/acme/jobs/101" }, "method": "POST", "path": "/api/job-resumes/pick" }, "run_posting": { "method": "GET", "path": "/api/runs/run_20260929T100000Z/posting?url=..." }, "self": { "method": "GET", "path": "/api/jobs?url=..." }, "suggestions": { "method": "GET", "path": "/api/jobs/suggestions?url=..." } }, "liveness": { "board_url": null, "checked_at": "2026-10-06T10:00:00Z", "closed_at": null, "company_page": "unknown", "company_page_note": null, "note": null, "state": "open" }, "open_questions": [ { "question": "Are you authorized to work in the US?", "question_id": "auth:work_authorization", "requirement": null } ], "posting": { "company": "Acme", "company_name": "Acme", "company_slug": "acme", "location": "Remote - US", "normalized_url": "https://boards.greenhouse.io/acme/jobs/101", "text": "...", "title": "Software Engineer" }, "rank": { "blockers": [], "demoted": false, "normalized_url": "https://boards.greenhouse.io/acme/jobs/101", "reasons": [ "Python" ], "score": 82, "unscored_reason": null }, "rank_score": null, "runs": [ { "outcome": "new", "run_id": "run_20260929T100000Z" } ], "schema_version": "scout-job-response:1", "tags": [ { "label": "Staff Engineer", "match_rank": 1, "profile_id": "prof_1", "rank_score": 82 } ], "tailored_resumes": [ { "company": "Acme", "created_at": "2026-09-29T10:05:00Z", "job_identity": "https://boards.greenhouse.io/acme/jobs/101", "links": { "line": { "body": { "job_identity": "https://boards.greenhouse.io/acme/jobs/101", "line_id": "<L id from the resume>", "updated_at": "2026-09-29T10:05:00Z", "use": "original" }, "method": "PUT", "path": "/api/tailored-resumes/lines" }, "pdf": { "body": { "job_identity": "https://boards.greenhouse.io/acme/jobs/101" }, "method": "POST", "path": "/api/tailored-resumes/pdf" } }, "profile_id": "prof_1", "title": "Software Engineer", "updated_at": "2026-09-29T10:05:00Z" } ], "work_mode_fit": null}Forbidden_origin
object
object
Example
{ "error": { "code": "forbidden_origin", "message": "..." }}Not_found, target_unavailable
object
object
Example
{ "error": { "code": "not_found", "message": "..." }}Invalid_value, unknown_key
object
object
Example
{ "error": { "code": "invalid_value", "message": "..." }}