Save Extracted Job
store_extracted_jdSave a job description you already extracted as structured JSON so it can be scored, matched, and tracked—no extra LLM parsing required.
Instructions
Store a job description the caller already extracted into JSON (the backend makes no LLM call).
extracted_json must match the app's JobExtraction schema: company, title,
role_category, level: "intern"|"entry"|"mid"|"senior"|"lead" (other spellings
map to these; any other level is kept in its own words), employment_type,
work_mode: "remote"|"hybrid"|"on_site" (stored as that key), city/state/country
(the job also stores country_code, the one ISO code they name),
location_raw, salary_min/max, salary_period, salary_currency (ISO 4217; a bare "$"
is no currency, so the job takes its country's, else the home one, and
salary_currency_assumed is true),
work_authorization: "sponsorship_available"|"no_sponsorship"|"citizen_or_gc_required"|"unstated",
opt_accepted: "yes"|"stem_opt_ok"|"no"|"unstated",
years_experience_min/max, skills[{skill_name, skill_category,
requirement_level: "required"|"preferred"|"mentioned"}],
responsibilities[], qualifications[]. ANY other work_authorization or
opt_accepted value silently normalizes to "unstated" with no error.
source is "user" (default) or "agent"; source="agent" marks agent-hunted jobs,
which need an open proposal before the apply helpers act on them. A job
stored with source="user" is not proposal-gated: the server skips the
open-proposal check for any non-agent source. Returns the stored job.
A posting already saved is returned unchanged with already_existed=true,
unless update=true: then this extraction corrects it and the job carries
correction. Already saved means the same raw_text (with none, the same
extraction or the same posting at source_url) or the same company and
requisition_id.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | No | user | |
| update | No | True: when the posting is already saved, this extraction replaces that job's fields and skills through the same mapping a new capture uses; the job keeps its id, status, applications, proposals, source and raw_text. It overwrites the stored extraction, which the web app can't undo. The saved job is found the way a capture finds it: resend the saved raw_text, or omit raw_text and pass its source_url (new raw_text misses the text match and creates a new job). The response's correction is {changed: the fields whose value changed, "skills" when the skill list did; scores_cleared: the job's match scores deleted because a field scoring reads changed, after which the job is scored again; rescored: true when that succeeded; rescore_failed: "bases" or the application ids it could not score, which score_ats computes later; tailored_applications: tailored resumes, left as written; open_sessions: open gap analyses, left to read as out of date, with their score link cleared; proposals_fit_stale: proposals whose stored fit predates the correction}. A job another copy of Maestro owns is refused (409). False (default): a repeat capture returns the saved job unchanged. | |
| raw_text | No | ||
| apply_url | No | The posting's application address when it differs from source_url (http or https). Stored with the job; find_job_by_url then finds the job by it when the address names the posting (an id in its path or query). Without update, a saved job takes it only when it has none; with update it replaces the stored one. | |
| source_url | No | ||
| extracted_json | Yes |