---
title: "Create job"
method: POST
path: "/jobs"
tags: ["Jobs"]
---

# Create job

`POST /jobs`

## Request

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

Creates a job with taxonomy, location, salary, and workflow configuration. Primary endpoint for programmatic job publishing workflows.

## Query parameters

- `include` string

## Request body

- JobCreateRequest
  - `company_id` integer: Target company ID. Required only when the API key has access to multiple companies.
  - `form_id` integer: Application form ID. If omitted, a new form named after the job title is created with default questions (First name, Last name, Email, Phone).
  - `status` string, required: Job status (e.g. Draft, Public). See GET /taxonomy/statuses.
  - `title` string, required: 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, required: 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 it or send null to 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.
  - `location_country` string, required: 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. If omitted, a new workflow named after the job title is created with default stages.
  - `parent_job_id` integer: Canonical parent job ID. If provided, the created 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. Providing this field is a full replace: existing criteria are detached (preserved if used in past evaluations, soft-deleted otherwise) and the supplied list becomes the current set. Omit the field to leave defaults untouched. Pass an empty array to detach all criteria.
    - `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`

Created 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
- `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)
