---
title: "Create job post"
method: POST
path: "/v3/job_posts"
tags: ["Job Posts"]
---

# Create job post

`POST /v3/job_posts`

Create a new job post by duplicating an existing one. The new post is attached to the same parent job as the template (`template_job_post_id`) and published to the supplied `job_board_id`. Use this to spin up additional language, geography, or board variants of a job's listing without re-entering the content, application questions, or settings. To create the first post on a job, post a template from another job and adjust the resulting post; this endpoint does not create a post from scratch.

## Request body

- object
  - `template_job_post_id` integer, required — Id of an existing job post to duplicate. The new post is created on the same parent job as the template and copies its content, questions, and configuration. The template post itself is unchanged.
  - `title` string — Public-facing title for the new post. Defaults to the template post's title when omitted.
  - `content` string, nullable — HTML body of the post shown to candidates. Sanitized server-side — only a limited element/attribute allowlist (including `iframe`, `video`, `source`) survives. Pass `null` or omit to inherit the template's content.
  - `internal` boolean, nullable — If `true`, create the post on the organization's internal job board (employees only). If `false` or `null`, the post is external. Must be consistent with `job_board_id` — internal job boards only accept internal posts.
  - `status` 'draft' | 'live' — Initial publication status. Use `live` to publish immediately or `draft` to save as an unpublished working copy. Defaults to `draft`.
  - `demographic_question_set_id` integer, nullable — Id of the demographic question set to attach to the new post for DE&I reporting. Pass `null` to opt out of demographic questions.
  - `job_board_id` integer, required — Id of the `job_board` to publish the post to. A single post belongs to one board at a time; resolve available boards via `GET /v3/job_boards`.

## Response `201`

Successful

- object
  - `id` integer
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `title` string — Public-facing title shown to candidates on the job board (e.g. `Senior Backend Engineer, Remote`). Distinct from the internal `job.name` — a single job can have several posts with different titles, one per board, language, or geography.
  - `internal` boolean — If `true`, the post lives on an internal job board and is visible only to existing employees signed in to the internal board. If `false`, the post is external and lives on a public-facing `job_board`. Set by the board the post is associated with at create time.
  - `active` boolean — If `true`, the post has not been deleted. Deleted posts are excluded by default; pass `active=false` on the list endpoint to retrieve them.
  - `live` boolean — If `true`, the post is published (`job_application_status` is `live`) and its job board is also live. A post on an unpublished board is **not** `live` — its `public_url` returns a 404 until the board is enabled.
  - `featured` boolean — If `true`, the post is currently featured on the organization's internal job board and surfaces in the weekly internal-jobs email. Only internal posts can be featured, and at most three can be featured at a time.
  - `first_published_at` string, date-time, nullable — Timestamp the post first transitioned to `live`, in ISO 8601. `null` for posts that have never been published.
  - `content` string, nullable — HTML body of the post shown to candidates on the job board. For internal posts this returns the `internal_content` instead. Sanitized server-side — only a limited element/attribute allowlist (including `iframe`, `video`, `source`) survives. `null` while the post is still being scaffolded.
  - `internal_content` string, nullable — HTML body shown on the internal job board when the post is also configured as internal. `null` for external-only posts. Same sanitization rules as `content`.
  - `language` 'en' | 'zh' | 'zhHant' | 'nl' | 'fi' | 'fr' | 'de' | 'iw' | 'it' | 'ja' | 'ko' | 'no' | 'pl' | 'pt' | 'ru' | 'es' | 'se' | 'tg' | 'th', nullable — ISO 639-1 locale of the post, used to render the candidate-facing application form in the matching language (e.g. `en`, `fr`, `ja`). `null` when no locale has been chosen.
  - `public_url` string, uri, nullable — Canonical public URL of the post on its job board, including the `gh_jid` tracking parameter. `null` when the post has no associated job board or the board has no public URL configured.
  - `demographic_question_set_id` integer, nullable — Id of the demographic question set surfaced to candidates on this post for diversity, equity, and inclusion (DE&I) reporting. `null` when the post does not collect demographic data.
  - `job_id` integer — Id of the parent job (requisition) this post belongs to. A single job can have multiple posts; the job is the source of truth for the hiring team, openings, and interview plan.
  - `job_board_id` integer — Id of the `job_board` this post is published to. Resolves to either an external (careers site, syndicated board) or internal job board depending on `internal`. Each post belongs to exactly one board at a time.
  - `questions` object[] — Application form questions presented to candidates on this post, including default questions (resume, cover letter, basic info) and any custom questions configured by the hiring team. Ordered as they appear on the form.
    - `id` integer, nullable — Id of the question. `null` for default questions that are rendered from configuration rather than persisted per post (e.g. the built-in `first_name` field).
    - `description` string, nullable — Help text shown below the question label to give candidates additional context. `null` when no help text is set.
    - `answer_type` 'short_text' | 'long_text' | 'boolean' | 'single_select' | 'multi_select' | 'attachment' | 'hidden' — Input type the candidate uses to answer. `short_text` and `long_text` are free-text inputs, `single_select` and `multi_select` use the `options` array, `boolean` is a yes/no, `attachment` accepts a file upload, and `hidden` is set programmatically without rendering a field.
    - `required` boolean, nullable — If `true`, the candidate must answer this question to submit the application. `null` for default questions whose required-ness is driven by board-level configuration.
    - `private` boolean — If `true`, answers to this question are visible only to users with explicit access (e.g. private notes, API-only questions). Defaults to `false`.
    - `label` string — Human-readable label rendered above the input on the application form.
    - `name` string — Stable form-field name used when submitting an application (e.g. `question_42` for a custom question, `first_name` for a default field). Use this when mapping responses back to a question.
    - `options` object[] — Selectable answer options for `single_select` and `multi_select` questions. Empty for other answer types.
      - `id` integer — Id of the option, stable across edits to the option label.
      - `label` string — Human-readable text shown to the candidate for this option.

## Other responses

- `401` — Unauthorized
- `403` — Forbidden
- `422` — Unprocessable Content

---

[API](https://skmtc.dev/greenhouse/apis/auth-api.md) · [All operations](https://skmtc.dev/greenhouse/apis/auth-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/greenhouse/auth-api/revisions/9517a2e54640/schema)
