---
title: "Update job"
method: PUT
path: "/jobs/{id}"
tags: ["Jobs"]
---

# Update job

`PUT /jobs/{id}`

## Request

- Base URL: `https://api.100hires.com/v2`
- URL: `https://api.100hires.com/v2/jobs/{id}`
- Auth: HTTP bearer

Updates mutable job attributes. Preserves domain-level validation rules.

## Path parameters

- `id` string, required

## Query parameters

- `include` string

## Request body

- JobUpdateRequest
  - `form_id` integer: Application form ID to assign to this job. Replaces the job's active form; the previous link is kept inactive. The response's `form_id` reflects the new form.
  - `status` string: Job status (e.g. Draft, Public). See GET /taxonomy/statuses.
  - `title` string: Public job title.
  - `internal_title` string: Internal-only title visible to the hiring team.
  - `internal_job_id` string: External reference ID from your ATS or HR system.
  - `description` string: Job description (HTML allowed).
  - `language` string, nullable: Locale the job page renders in, overriding the career site language (e.g. de-DE; underscore aliases like de_DE are normalized). Omit the field to leave the current override untouched; send null to remove it and follow the career site language. Unknown, disabled, empty and longer-than-35-character values are rejected with a 400 validation error on `language`. Available locales come from GET /languages.
  - `resume_field_status` 'required' | 'optional' | 'hidden': Resume field behavior on the application form.
  - `location_city` string: Job city. Required unless is_remote is true; leave city, state and postal code empty for a nationwide remote posting on Indeed. Street, city, state, postal code and country are validated together on save, the same way the back-office form checks them: with Google Address Validation in the countries it covers, with a geocoding provider elsewhere. A confirmed location is stored as validated, so a misspelt city is corrected; a location that is unknown, suspicious (for example a city in the wrong state) or would need a part replaced is stored as sent, and the job boards tab of the job reports it until it is fixed. Components that are already confirmed are not checked again.
  - `location_country` string: Job country: a country name or an ISO 3166-1 alpha-2 code from the country list. Anything else is rejected with a validation error.
  - `location_state` string: Job state or region.
  - `location_street_address` string: Street address.
  - `location_full_address` string: Accepted and ignored: the job address is assembled from street, city, state, postal code and country. Kept for compatibility.
  - `location_postal_code` string: Postal or ZIP code.
  - `salary_min` number: Minimum salary.
  - `salary_max` number: Maximum salary.
  - `salary_currency` string: Salary currency code (e.g. USD, EUR).
  - `salary_period` 'annually' | 'monthly' | 'daily' | 'hourly': Salary period. A job created without it is "annually". An "annually" salary with an amount below 1000 is rejected as an hourly rate typed against the yearly period: send "hourly" instead.
  - `is_remote` boolean: Whether this is a remote position. With an empty city, state and postal code Indeed lists it nationwide.
  - `is_hybrid` boolean: Hybrid position: office days plus remote days at the job address, so location_city stays required. Requires is_remote false; sending both as true is rejected, and is_remote true on a hybrid job clears is_hybrid. Indeed lists it as Hybrid Remote, LinkedIn as Hybrid, other boards as an on-site job at that address.
  - `job_board_remote_scope` 'city' | 'statewide' | 'nationwide' | 'null', nullable: How a remote job is listed on Indeed: city (default) keeps the address, statewide sends the state alone, nationwide the country alone. Other boards always get the full address. Non-city requires is_remote true, statewide also location_state; null resets to city.
  - `employment_type_id` integer: Employment type ID from GET /taxonomy/employment-types.
  - `department_id` integer: Department ID from GET /taxonomy/departments.
  - `category_id` integer: Job category ID from GET /taxonomy/categories.
  - `education_level_id` integer: Education level ID from GET /taxonomy/education-levels.
  - `experience_level_id` integer: Experience level ID from GET /taxonomy/experience-levels.
  - `workflow_id` integer: Workflow ID to assign to this job.
  - `parent_job_id` integer: Canonical parent job ID. If provided, the job becomes a satellite job.
  - `knockout_questions` object[]: Boolean knockout questions added to the application form. Each question with `disqualify_on_wrong_answer=true` creates an auto-disqualify rule on the Applied stage.
    - `text` string, required: Question text shown to the applicant.
    - `expected_answer` 'Yes' | 'No', required: The correct/desired answer.
    - `disqualify_on_wrong_answer` boolean, required: If true, applicants who answer incorrectly are automatically disqualified.
  - `ai_scoring_criteria` AiScoringCriterionInput[]: AI scoring criteria for evaluating candidates against this job. Diff-replace by `id`: items with `id` update the matching existing criterion (preserving identity), items without `id` create new criteria, and existing criteria not referenced in the payload are removed. Omit the field to leave existing criteria untouched. Pass an empty array to detach all criteria. Each item's order in the array becomes its `position`.
    - `id` integer: ID of an existing criterion attached to this job. When present, the corresponding criterion is updated in place (or, if it has scores, detached and replaced — `ManageCriteria::createOrUpdate` semantics). Omit `id` to create a new criterion. Items existing on the job that are not present in the request (matched by `id`) are removed (soft-deleted if unscored, detached if used in past evaluations).
    - `title` string: Optional short label for the criterion.
    - `text` string, required: Prompt text describing what to evaluate. Required.
    - `weight` integer, required: Relative importance of this criterion in the total score (1–10).

## Response `200`

Updated job

- Job
  - `id` integer, required: Unique identifier
  - `alias` string, nullable: Short alphanumeric alias used in UI URLs. Use this to build job links — `https://app.100hires.com/job/{alias}/candidates/pipeline`. Also accepted as `{id}` in API requests.
  - `company_id` integer, required: ID of the company this job belongs to
  - `title` string, required: Public job title shown to candidates
  - `internal_title` string, nullable: Internal job title visible only to the hiring team
  - `internal_job_id` string, nullable: Company's internal job identifier (e.g. requisition number)
  - `description` string: Job description (HTML). Present only when `view=full` (default); omitted entirely when `view=summary` to keep list responses inside the agent context budget. Use `GET /jobs/{id}` or `view=full` to retrieve.
  - `resume_field_status` 'required' | 'optional' | 'hidden', nullable: Whether resume upload is required, optional, or hidden on the application form
  - `location` JobLocation
    - `country` string: Country.
    - `city` string: City.
    - `state` string: State or region.
    - `postal_code` string: Postal code.
    - `street_address` string: Street address.
    - `full_address` string: Full formatted address.
  - `url` string, required: Public URL of the job posting page
  - `url_backoffice` string: Backoffice URL — opens the job's pipeline view inside the recruiter app (`https://app.100hires.com/job/{alias}/candidates/pipeline`). Use this to link agent widgets / UI to the in-app job page rather than the public career page.
  - `is_remote` boolean, required: Whether this is a remote position
  - `is_hybrid` boolean, required: Whether this is a hybrid position: office days plus remote days at the job address. Never true together with is_remote.
  - `job_board_remote_scope` 'city' | 'statewide' | 'nationwide', nullable: How a remote job is listed on Indeed: city, statewide or nationwide. Null when the job is not remote.
  - `status` string, required: Job status: open, closed, draft, or archived
  - `department` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `category` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `employment_type` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `education_level` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `experience_level` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `workflow_id` integer, nullable: ID of the hiring workflow (pipeline) assigned to this job
  - `workflow` IdName
    - `id` integer, required: Unique identifier.
    - `name` string, required: Display name.
  - `form_id` integer, nullable: ID of the application form candidates fill in for this job — the form attached to the job, or the company default form when the job has none attached yet (the same rule the public apply page follows). `null` only when the company has no forms. Fetch the questions with `GET /forms/{id}`. Present in both `view=full` and `view=summary`.
  - `pipeline_stages` object[], nullable: Pipeline stages for this job's workflow. Only included when `include=pipeline_stages` is specified. Suppressed when `view=summary` even if the include was requested.
    - `id` integer
    - `name` string
  - `salary_min` number, nullable: Minimum salary
  - `salary_max` number, nullable: Maximum salary
  - `salary_currency` string, nullable: Salary currency code (e.g. USD, EUR)
  - `salary_period` 'annually' | 'monthly' | 'daily' | 'hourly', nullable: Salary period
  - `hours_per_week_min` integer, nullable: Minimum hours per week
  - `hours_per_week_max` integer, nullable: Maximum hours per week
  - `indeed_posting_data` object: Indeed job board posting metadata. Present only when `view=full` (default); omitted entirely when `view=summary`.
  - `hiring_team` JobHiringTeamMember[]: Team members assigned to this job. Embedded via `include=hiring_team`. Suppressed when `view=summary` even if the include was requested.
    - `id` integer, required: User ID.
    - `full_name` string, required: User full name.
    - `email` string, nullable: User email.
    - `role` string, nullable: Role on hiring team (e.g. hiring_manager, recruiter).
  - `is_satellite` boolean: Whether this job is a satellite (child) of a canonical job. Satellite jobs share the candidate pipeline of their parent.
  - `parent_job_id` integer, nullable: ID of the canonical (parent) job. Null for canonical jobs. Recruiting operations should target the canonical job.
  - `language` string, nullable: Locale this job's public page renders in, overriding the career site language. Null means the page follows the career site language (`GET /companies/career-site-settings`), which in turn falls back to en-US. This is the override, not the effective language. Present in both `view=full` and `view=summary`.
  - `created_at` integer, required: Unix timestamp (seconds)
  - `updated_at` integer, required: Unix timestamp (seconds)
  - `ai_scoring_criteria` AiScoringCriterion[]: AI scoring criteria configured for this job, ordered by `position` ASC. Returned as an empty array when none are configured. Present only when `view=full` (default); omitted entirely when `view=summary`.
    - `id` integer, required: Unique identifier of the criterion.
    - `title` string, nullable: Optional short label for the criterion.
    - `text` string, required: Prompt text describing what to evaluate.
    - `weight` integer, required: Relative importance of this criterion in the total score (1–10).
    - `position` integer, required: 0-based ordinal of the criterion in the job's list.

## Other responses

- `400`: Validation error
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `415`: Content-Type must be application/json
- `429`: Too many requests

---

[API](https://skmtc.dev/100hires/apis/100hires-api.md) · [All operations](https://skmtc.dev/100hires/apis/100hires-api/llms.txt) · [OpenAPI document](https://skmtc.dev/100hires/apis/100hires-api/revisions/e63e2d3115f7?raw)
