Assess one job against a resume
const url = 'http://127.0.0.1:8765/api/assess';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"job":{"job_url":"https://boards.greenhouse.io/acme/jobs/101"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://127.0.0.1:8765/api/assess \ --header 'Content-Type: application/json' \ --data '{ "job": { "job_url": "https://boards.greenhouse.io/acme/jobs/101" } }'Assess one job (URL or pasted text) against a resume: verdict, requirement matrix, questions. Synchronous: blocks for the model call (and a public fetch for job_url). Stores the assessment; read it back with GET /api/jobs?url=. 0.1.11.4: a job_url whose board no longer lists the posting (GET /api/jobs liveness.state: closed) answers 409 posting_closed with that liveness and makes no model call; pasted job_text is always assessed. An error whose code is model_target_unavailable, model_denied, model_unavailable, assess_timeout, model_output_invalid or assessment_not_stored also carries model_call_started, may_have_used_tokens, fresh_assessment_stored (always false) and next_action. This route does not ask first: POST /api/postings/assess without approve is the no-call preview of what an assessment sends. 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. A stored assessment records its basis (prompt_version, constraints_digest, story_bank: digests and ids, no settings or answer text). Served with basis_stale (true | false) and, when true, basis_stale_reason (older_prompt | settings_changed | story_bank_changed): whether it is what its profile would be assessed with now. Derived on read; no model is called. story_bank_changed is targeted: an answer or story added or edited since answers one of the assessment’s own open questions (the same id, the near match behind bank_suggestions, or a story about it), or it cites an answer or story that was edited or deleted. Such an item also carries basis_stale_bank: the entries that made it stale, each {match: "exact" | "near" | "cited", bank_question_id, bank_question?, question_id?, question?} (ids and question words, never an answer). With a master resume stored a fourth reason exists, resume_changed, targeted the same way: a resume line the assessment quoted as evidence is no longer in what its profile would be assessed with, or a line that was not there names the subject of one of its open questions. Such an item carries basis_stale_resume: each {change: "line_changed", requirement} or {change: "new_line", question_id, question?} (the assessment’s own words, never a resume line). An assessment that read the evidence view of the master carries resume_basis: {input: "evidence", master_revision_id, master_revision, selector_version}. An assessment whose answer read fewer than three requirements from a posting of 1,200+ characters (after one retry) is stored as the model gave it and carries requirements_note: “Only N requirements were read from this posting. Open the posting to check.” (omitted otherwise). A stored v9 assessment carries checks (0.1.11.4, omitted on older ones): counts of what the code checks did, no text and no ids: {settled_rows, settled_by_rule: {rule: n}, questions_dropped, questions_capped, suggestions_dropped: {reason: n}, citations_cleaned: {action: n}, questions_removed?: {reason: n}}.
Request Bodyrequired
Section titled “Request Bodyrequired”object
The posting: {"job_url": "<https url>"} or {"text": "<pasted posting>"}.
object
Which model target answers (claude or codex); omitted = the configured one.
Quick_assess | job_page.
Override the effective preferences.
object
Which resume: omitted = the selected profile; else {“profile_id”: “…”} or pasted resume text.
object
Optional; must equal the request schema version when present.
Example
{ "job": { "job_url": "https://boards.greenhouse.io/acme/jobs/101" }}Responses
Section titled “Responses”Success.
object
Example
{ "job": { "job_identity": "https://boards.greenhouse.io/acme/jobs/101" }, "result": { "matrix": [], "questions": [], "suggestions": [], "verdict": "matched_above_threshold" }, "schema_version": "scout-assess-response:1"}Model_denied
object
object
Example
{ "error": { "code": "model_denied", "message": "..." }}Target_unavailable
object
object
Example
{ "error": { "code": "target_unavailable", "message": "..." }}Posting_closed
object
object
Example
{ "error": { "code": "posting_closed", "message": "..." }}Unsupported_media_type: writes need Content-Type: application/json.
object
object
Examplegenerated
{ "error": { "allowed_keys": [ "example" ], "code": "example", "message": "example" }}Invalid_value, wrong_type, unknown_key, job_input_invalid
object
object
Example
{ "error": { "code": "invalid_value", "message": "..." }}Assessment_not_stored
object
object
Example
{ "error": { "code": "assessment_not_stored", "message": "..." }}Job_fetch_failed, model_output_invalid
object
object
Example
{ "error": { "code": "job_fetch_failed", "message": "..." }}Model_unavailable
object
object
Example
{ "error": { "code": "model_unavailable", "message": "..." }}Assess_timeout
object
object
Example
{ "error": { "code": "assess_timeout", "message": "..." }}