---
title: "Create a job role with a competency rubric"
method: POST
path: "/api/public/v1/job-roles"
tags: ["Public API v1 — Job Roles", "Public API v1 — Job Roles"]
---

# Create a job role with a competency rubric

`POST /api/public/v1/job-roles`

## Request

- Base URL: `https://api.thebetterhire.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.thebetterhire.ai/api/public/v1/job-roles`
- Auth: HTTP bearer

Create the role an interview is scored against. Omit `competencies` and BetterHire extracts 5–7 from the job description — the same extraction the dashboard runs. Supply them to use your own rubric.

The response says whether an AI-led interview can be scheduled on the role (`interview_ready`) and the shortest slot it fits, so a rubric that would be rejected at scheduling time is caught here.

`title` may be omitted: the extraction reads the title, level and company off the posting and returns them as `inferred` (validated; null when the text does not say). One role per title: a second role with the same title would make every `role`-by-title call on this API ambiguous, so that returns 409 with the existing role's id.

Rate limit: 50 requests/hour per API key. Supports `Idempotency-Key`.

## Request body

- BackendRoutersPublicJobRolesJobRoleCreateRequest
  - `title` string, nullable: Omit to use the title read off the posting (`inferred.title`). 422 TITLE_REQUIRED when the text does not name the role either.
  - `job_description` string, required: Full job description text. Competencies are extracted from it unless you supply them.
  - `competencies` CompetencyInput[], nullable: Omit to have BetterHire extract 5–7 competencies from the job description. Supply your own to use them as given; they are validated against the interview engine's rules before anything is saved.
    - `name` string, required
    - `description` string, required: What good looks like. Drives the interviewer's probing questions, so it needs at least 20 characters of substance.
    - `importance` integer: 1–5. Competencies rated 4 or 5 are must-cover: the interviewer will not skip them, so each one costs interview time.
    - `evaluation_criteria` string, nullable
  - `experience_level` string, nullable: entry, mid, senior, lead or executive. Sets the seniority the candidate is judged against and how deep the interview probes. Defaults to mid.
  - `company_name` string, nullable: Hiring company shown to candidates, when it is not your own organisation (agencies).

## Response `201`

Successful Response

- BackendRoutersPublicJobRolesJobRoleResponse
  - `id` string, required
  - `title` string, required
  - `experience_level` string, nullable
  - `company_name` string, nullable
  - `competencies` Competency[], required
    - `name` string, required
    - `description` string, required
    - `importance` integer, required
    - `evaluation_criteria` string, nullable
  - `interview_ready` InterviewReadiness, required: Whether an AI-led (brain) interview can be scheduled on this role.
    - `ready` boolean, nullable, required: true: schedule with POST /interviews/schedule/brain. false: see `note`. null: the interview engine could not be consulted — retry GET /job-roles/{id}.
    - `min_duration_minutes` integer, nullable: Shortest slot the rubric fits in, when ready: 45, 60 or 90, or 30 for an entry-level role.
    - `note` string, nullable
  - `created_at` string, required
  - `updated_at` string, required
  - `inferred` InferredRole: What the extraction read off the posting (platform request 0003 §6d). Every field is validated in code; null means "the text does not say", never a guess. Sandbox roles infer from labelled lines only.
    - `title` string, nullable: The role title as a recruiter would write it, at most 120 characters; never a section heading or a line of punctuation. Null when the text does not name the role.
    - `experience_level` string, nullable: entry, mid, senior, lead or executive, when the text says.
    - `company_name` string, nullable: The hiring company, only when the text names one.
    - `skill_ids` string[]: Specialist skill packs the posting genuinely calls for (ids from GET /skills). Usually empty.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/thebetterhire/apis/interanalysis-b2b-api.md) · [All operations](https://skmtc.dev/thebetterhire/apis/interanalysis-b2b-api/llms.txt) · [OpenAPI document](https://skmtc.dev/thebetterhire/apis/interanalysis-b2b-api/revisions/c8ad03e900ea?raw)
