> ## Documentation Index
> Fetch the complete documentation index at: https://developer.jobmojito.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update an interview or position

> Updates the configuration of an existing interview (single-stage) or position (multi-stage). Only the fields present in the request body are written — everything else keeps its current value, and sending null clears a nullable field. The question list is only touched when you send `questions`; omit that field and the questions are left exactly as they are. When sent, it must be the complete list and is applied as a diff against what is stored (matched on external_id, then id, then identical content), so unchanged questions keep their existing records, edited ones are unlinked and re-created, and dropped ones are unlinked — and re-sending the array job-interview-get returned changes nothing. See the field description, and `questions_diff` in the response for what was decided. Questions of an interview that is already `active` can only be changed on interactive avatar templates, where re-publishing is instant; on the offline (pre-rendered video) templates set the interview back to `draft` first. The welcome / thank-you messages and the instructional-video screen are stored as steps rather than questions and are never changed here. `mojito_language_code` cannot be changed — the existing questions and rendered videos are in the original language — so create a new interview to change language. A multi-stage position only carries the shared identity fields (name, code, location, description, description_long, cover_image_url, department, salary, available_till, recruiter, status, visibility, hiring_for_company); sending an interview-only field for a position is a 422.



## OpenAPI

````yaml https://cool.jobmojito.com/functions/v1/openapi post /job-interview-update
openapi: 3.1.0
info:
  title: JobMojito API
  version: 1.0.0
  description: >-
    Public API for JobMojito, served by Supabase Edge Functions. Authenticate
    with a Supabase JWT access token via the Authorization header.
servers:
  - url: https://cool.jobmojito.com/functions/v1
    description: Production
security: []
tags:
  - name: Interviews
    description: >-
      Create, configure and manage interview / coaching / assessment
      definitions.
  - name: Coaching catalogue
    description: >-
      Directories (pages) of the coaching portal catalogue that group coaching
      sessions and carry custom content pages.
  - name: Results
    description: >-
      Interview results, transcripts, reports, re-attempt requests and
      analytics.
  - name: Candidates
    description: List and manage candidates.
  - name: Knowledge base
    description: Upload documents used to generate knowledge-base interviews.
  - name: Resume & Form verification
    description: Pre-screen candidates from resumes and forms.
  - name: Admin
    description: >-
      Account administration — invite team/coaching users, manage sub-merchants
      and avatar templates.
paths:
  /job-interview-update:
    post:
      tags:
        - Interviews
      summary: Update an interview or position
      description: >-
        Updates the configuration of an existing interview (single-stage) or
        position (multi-stage). Only the fields present in the request body are
        written — everything else keeps its current value, and sending null
        clears a nullable field. The question list is only touched when you send
        `questions`; omit that field and the questions are left exactly as they
        are. When sent, it must be the complete list and is applied as a diff
        against what is stored (matched on external_id, then id, then identical
        content), so unchanged questions keep their existing records, edited
        ones are unlinked and re-created, and dropped ones are unlinked — and
        re-sending the array job-interview-get returned changes nothing. See the
        field description, and `questions_diff` in the response for what was
        decided. Questions of an interview that is already `active` can only be
        changed on interactive avatar templates, where re-publishing is instant;
        on the offline (pre-rendered video) templates set the interview back to
        `draft` first. The welcome / thank-you messages and the
        instructional-video screen are stored as steps rather than questions and
        are never changed here. `mojito_language_code` cannot be changed — the
        existing questions and rendered videos are in the original language — so
        create a new interview to change language. A multi-stage position only
        carries the shared identity fields (name, code, location, description,
        description_long, cover_image_url, department, salary, available_till,
        recruiter, status, visibility, hiring_for_company); sending an
        interview-only field for a position is a 422.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JobInterviewUpdateRequest'
      responses:
        '200':
          description: Interview / position updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobInterviewUpdateResponse'
        '401':
          description: Missing, expired or invalid access token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Your token is not allowed to use this endpoint (it is not a
            merchant, merchant owner or admin token).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >-
            No interview or position found for the given id (or hidden by
            row-level security).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            Validation error (unknown enum value, out-of-range number,
            unresolved template/language/knowledge-base id, an interview-only
            field sent for a multi-stage position, an empty `questions` array,
            or a question change on an active interview using an offline avatar
            template).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    JobInterviewUpdateRequest:
      type: object
      properties:
        position_id:
          type: string
          minLength: 1
          format: uuid
          description: >-
            Id of the interview definition (single-stage) or position definition
            (multi-stage) to update. The same id you pass to job-interview-get.
          example: 00000000-0000-0000-0000-000000000000
        status:
          type: string
          enum:
            - draft
            - active
            - archived
            - deleted
            - preparing
            - completed
          description: >-
            New lifecycle status. Applied through the same interview_set_status
            routine as job-interview-set-state (which is also where you manage
            the iframe embed key).
          example: active
        visibility:
          type: string
          enum:
            - merchant_public
            - merchant_invite
            - merchant_unlisted
          description: >-
            Who can discover and access the interview. Options —
            `merchant_public`: Listed on the merchant's public interview list —
            anyone with the merchant link can find and start it. |
            `merchant_invite`: Invite-only — only candidates explicitly invited
            (by email/link) can access it; not listed anywhere. |
            `merchant_unlisted`: Reachable only via a direct link — not listed
            anywhere; share the link manually..
          example: merchant_public
        environment:
          type: string
          enum:
            - production
            - uat
            - development
            - demo
          description: >-
            Which of your webhook environments results from this interview are
            delivered to. Defaults to production. Options — `production`: Live
            hiring. Results reach the webhooks configured as production. This is
            the default when the field is omitted. | `uat`: User-acceptance
            testing - an isolated environment for pre-release verification. |
            `development`: Development/testing. Use for interviews created by a
            test or preview app so their results never reach the production
            webhook. | `demo`: Demonstrations and sales trials..
          example: production
        name:
          type: string
          nullable: true
          description: Interview / position name.
          example: Project manager
        code:
          type: string
          nullable: true
          description: External code/reference. Blank is stored as null.
        location:
          type: string
          nullable: true
          description: >-
            Interview location (column `interview_location`). Blank is stored as
            null.
          example: remote
        cover_image_url:
          type: string
          nullable: true
          description: Cover image URL.
        description:
          type: string
          nullable: true
          description: Short interview description.
        description_long:
          type: string
          nullable: true
          description: >-
            Long-form interview description (column
            `interview_description_long`). Rendered as Markdown on the
            candidate-facing position page, including chips, callouts, cards,
            columns and buttons — formatting guide:
            https://developer.jobmojito.com/cookbooks/format-content-with-markdown
        interview_department:
          type: string
          nullable: true
          description: Department the position belongs to. Blank is stored as null.
          example: Engineering
        interview_salary:
          type: string
          nullable: true
          description: Salary range shown for the position. Blank is stored as null.
          example: $80k - $100k
        interview_available_till:
          type: string
          nullable: true
          description: >-
            ISO date/time after which the interview is no longer available to
            candidates. null keeps it always available.
          example: '2026-12-31'
        recruiter_profile_id:
          type: string
          nullable: true
          description: >-
            Profile id of the recruiter owning this interview. Must be a
            merchant/merchant_owner/admin profile of the same merchant. null
            clears it.
        candidate_notification_channel:
          type: string
          nullable: true
          enum:
            - reminders
            - last_reminder
            - all
          description: >-
            SMS / WhatsApp notifications to the candidate, sent alongside the
            e-mails: "reminders" = with both e-mail reminders (day 1 and day 3);
            "last_reminder" = only with the final day-3 reminder; "all" =
            invitation, both reminders and the pre-screening-accepted step. null
            switches them off. WhatsApp is tried first, SMS when the number is
            not on WhatsApp. Available on paid plans (Starter and above) and
            needs a phone number on the candidate.
        country_availability:
          type: object
          nullable: true
          properties:
            countries_allowed:
              type: array
              items:
                type: string
                pattern: ^[A-Za-z]{2}$
              description: >-
                Available ONLY to candidates in these countries (ISO 3166-1
                alpha-2).
              example:
                - PH
                - IN
            countries_allowed_eu:
              type: boolean
              description: >-
                Adds every EU country (plus EEA and Switzerland) to
                countries_allowed.
            countries_blocked:
              type: array
              items:
                type: string
                pattern: ^[A-Za-z]{2}$
              description: >-
                NOT available to candidates in these countries (ISO 3166-1
                alpha-2). Wins over the allowed side.
              example:
                - US
            countries_blocked_eu:
              type: boolean
              description: >-
                Adds every EU country (plus EEA and Switzerland) to
                countries_blocked.
          description: >-
            Which countries the interview / position is open to on the candidate
            portal, judged by the IP address the candidate opens it from (an
            unknown location only passes when countries_allowed /
            countries_allowed_eu are empty). From a closed country it is left
            out of the portal listings, and a direct link shows "not available
            in your region". Invited candidates (register_users / invite links)
            and candidates who already started keep access; API and MCP calls
            themselves are never restricted. Null = not used, every country.
        tags:
          type: array
          nullable: true
          items:
            type: string
          description: >-
            Free-form tags stored on the interview. Tags are also the
            coaching-catalogue mapping key: a catalogue directory (see the
            catalogue-tag-create / catalogue-tag-update endpoints) lists a
            coaching or persona session when the session's tags contain EVERY
            tag in that directory's `tags_interview_set_filter`. Only `active`
            sessions with visibility `public` or `merchant_public` are listed.
          example:
            - interview-practice
            - sales
        questions:
          type: array
          items:
            $ref: '#/components/schemas/JobInterviewCreateFromArrayQuestion'
          minItems: 1
          description: >-
            OPTIONAL. Omit this field entirely and the interview's questions are
            left exactly as they are — this endpoint only touches questions when
            you send the array. When you do send it, send the COMPLETE list you
            want the interview to end up with, in order, in the same format
            job-interview-create-from-array accepts and job-interview-get
            returns: there is no way to change a single question on its own, so
            read the interview, edit that array, and send the whole thing back.
            An empty array is rejected. It is applied as a DIFF, not a replace,
            so resending the array job-interview-get gave you changes nothing at
            all. Each entry is matched against what is stored — first on
            `external_id`, then on `id`, then on identical content — and: an
            entry matching an unchanged question keeps that question exactly as
            it is, including its answer rules and any rendered avatar video; an
            entry matching a question whose content differs unlinks the old
            question and creates a new one in its place (fields you omit are
            carried over from the old one); an entry matching nothing is
            created; and a stored question no entry matches is unlinked.
            `questions_diff` in the response reports exactly what was decided.
            Questions are shared records, so nothing is ever deleted — removing
            one only unlinks it from this interview, and an edit is always
            unlink-old + create-new so the change cannot leak into another
            interview reusing the same question. The welcome, thank-you and
            instructional-video steps are not part of this array and are left in
            place. Single-stage interviews only; for a multi-stage position,
            update its interview stages individually.
        regenerate_candidate_expectations:
          type: boolean
          description: >-
            Re-derive the interview-level `candidate_expectations_json` scoring
            rubric from the resulting question list, the way
            job-interview-create-from-array derives it at creation time. Only
            applies when `questions` is sent, the interview type is `interview`,
            and `candidate_expectations_json` is not also being set explicitly
            (an explicit value wins).
          example: false
        type:
          type: string
          enum:
            - interview
            - coaching
            - assessment
          description: >-
            Product type of the interview. Changing it also re-derives
            `type_credit` (null for interview/assessment, otherwise
            interview_coach_manager) unless you send `type_credit` explicitly.
            Single-stage interviews only.
          example: interview
        type_credit:
          type: string
          nullable: true
          enum:
            - resume_check
            - interview_coach_starter
            - interview_coach_contributor
            - interview_coach_manager
            - cover_letter
          description: >-
            Credit bucket the session draws from. Only meaningful for
            candidate-paid coaching/persona sessions; hiring interviews and
            assessments are merchant-billed and carry null. Options —
            `resume_check`: Resume-check credits. | `interview_coach_starter`:
            Coaching credits — starter tier. | `interview_coach_contributor`:
            Coaching credits — contributor tier. | `interview_coach_manager`:
            Coaching credits — manager tier. | `cover_letter`: Cover-letter
            credits..
          example: interview_coach_manager
        coach_plan:
          type: string
          nullable: true
          enum:
            - demo
            - screening
            - 2nd
            - 3rd
            - closing
            - job-specific
            - other
          description: >-
            Coaching-plan stage this item belongs to, used by the coaching-plan
            progress view. Omit/null to leave it out of any plan. Options —
            `demo`: Demo session. | `screening`: Screening-interview practice. |
            `2nd`: Second-interview practice. | `3rd`: Third-interview practice.
            | `closing`: Closing / salary-negotiation practice. |
            `job-specific`: Job-specific coaching. | `other`: Anything that does
            not fit the other buckets..
          example: screening
        interview_template_id:
          type: string
          minLength: 1
          description: >-
            Id of the interview template (avatar/voice) to use. Must reference
            an existing interview_templates row. Also decides the modality — see
            list_avatars / merchant-avatar-list.
          example: 46b98d37-1557-4391-beca-03037ead19f2
        knowledge_base_store_id:
          type: string
          nullable: true
          description: >-
            Knowledge base store id the interview draws context from; validated
            for existence. null unlinks it.
        recording:
          type: string
          nullable: true
          enum:
            - audio_first_5_answers
            - audio_all
            - video_all
            - video_first_5_answers
          description: >-
            Cheating/proctoring detection mode for candidate answers — this is
            NOT a full session recording. Video options also record the
            candidate. Omit/null to disable. Options — `audio_first_5_answers`:
            Audio-only cheating detection, first 5 answers only. | `audio_all`:
            Audio-only cheating detection on every answer. | `video_all`: Audio
            + video cheating detection on every answer (candidate is recorded
            for all answers). | `video_first_5_answers`: Audio + video cheating
            detection, first 5 answers only..
          example: video_all
        recording_full_session:
          type: string
          nullable: true
          enum:
            - audio_all
            - video_all
          description: >-
            Full interview-session recording (includes the avatar and voice)
            produced as a single file. Independent of `recording`. Omit/null to
            disable. Options — `audio_all`: Record the whole session audio
            (avatar + candidate voice) into a single file. Adds +0.2 credits. |
            `video_all`: Record the whole session video + audio (avatar +
            candidate) into a single file. Adds +0.4 credits..
          example: video_all
        result_view:
          type: string
          enum:
            - none
            - minimal
            - minimal_with_score
            - advanced
            - full
            - full_expand_scores
          description: >-
            Result screen shown to the candidate after finishing. With any value
            other than `none`, the candidate sees a results screen where they
            can provide feedback, record an intro video and edit the transcript,
            and must then submit the result; the value sets how much
            score/result detail is shown. Options — `none`: No results screen at
            all — the interview is submitted immediately when the candidate
            finishes (no feedback, intro video, transcript edit or manual submit
            step). | `minimal`: Minimal results layout, no score shown. |
            `minimal_with_score`: Minimal results layout including the overall
            score. | `advanced`: Advanced results layout with more detail. |
            `full`: Full results layout with all sections. |
            `full_expand_scores`: Full results with every score breakdown
            expanded..
          example: full
        candidate_video_introduction:
          type: string
          nullable: true
          enum:
            - hidden
            - optional
            - required
          description: >-
            Whether a candidate video introduction is hidden, optional or
            required. null is treated like hidden.
        interview_conversation_speed:
          type: string
          nullable: true
          enum:
            - slower
            - normal
            - faster
          description: >-
            Conversation pace of the AI avatar. Omit/null keeps the template
            default pace. Options — `slower`: The avatar speaks more slowly —
            easier to follow for non-native speakers. | `normal`: Default
            speaking pace. | `faster`: The avatar speaks more quickly for a
            snappier conversation..
          example: normal
        max_followups:
          type: integer
          nullable: true
          minimum: 0
          maximum: 999
          description: >-
            Maximum number of AI follow-up questions. 0 disables follow-ups;
            presets are 0-3 (none/low/normal/high) and custom values start at 4;
            null uses the template default (Normal).
          example: 2
        max_duration:
          type: number
          nullable: true
          description: >-
            Live session limit in seconds. Also the basis for the credit
            multiplier.
          example: 1200
        questions_random_subset:
          type: number
          nullable: true
          minimum: 0.01
          maximum: 0.9
          description: >-
            Ask only a random subset of the questions, as a fraction between
            0.01 and 0.9. null asks all questions.
          example: 0.5
        interview_attempts:
          type: number
          minimum: 1
          maximum: 20
          description: >-
            Allowed candidate attempts (1-20). Stored as
            result_scoring.max_retries.
          example: 1
        required_pronunciation:
          type: boolean
          nullable: true
          description: >-
            Require pronunciation assessment (restricts to pronunciation-capable
            languages).
        result_enable_edit_transcript:
          type: boolean
          nullable: true
          description: Allow editing the transcript on the result view.
        candidate_expectations:
          type: string
          nullable: true
          description: Free-text candidate expectations.
        candidate_expectations_json:
          type: object
          nullable: true
          properties:
            weak:
              type: array
              items:
                type: string
              description: >-
                Baseline requirements every viable candidate should meet (table
                stakes).
            moderate:
              type: array
              items:
                type: string
              description: Requirements expected of a solid, competent candidate.
            strong:
              type: array
              items:
                type: string
              description: High-bar requirements only standout candidates clear.
          description: >-
            Structured candidate expectations (the scoring rubric), bucketed by
            requirement level (weak/moderate/strong). null clears the rubric.
            Extra keys are preserved.
        custom_scoring:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
          description: >-
            Result-scoring overrides (max_score, early_stop, speech_cadence,
            ai_pronunciation, sentiment_analysis, ai_assessment_answer,
            ai_assessment_resume, ai_assessment_session). Merged onto the stored
            configuration, so keys you omit keep their current value.
        pdf_export_auto_config:
          type: object
          nullable: true
          properties:
            mojito_language_code:
              type: string
              enum:
                - ar
                - bg
                - zh
                - hr
                - cs
                - da
                - nl
                - en
                - fil
                - fi
                - fr
                - de
                - el
                - hi
                - hu
                - id
                - it
                - ja
                - ko
                - ms
                - 'no'
                - pl
                - pt
                - br
                - ro
                - ru
                - sk
                - es
                - sv
                - ta
                - th
                - tr
                - uk
                - vi
              description: Report language code (a platform-languages.json code).
              example: en
            contact_details:
              type: boolean
              description: Include candidate contact details.
            ai_recruiter_assessment:
              type: boolean
              description: Include the AI recruiter assessment.
            ai_scoring_rubric:
              type: boolean
              description: Include the AI scoring rubric.
            analytics:
              type: boolean
              description: Include analytics.
            files:
              type: boolean
              description: Include uploaded candidate files.
            transcript:
              type: boolean
              description: Include the interview transcript.
            answer_recording:
              type: boolean
              description: Include per-answer recordings.
            session_recording:
              type: boolean
              description: Include the full-session recording.
            group_by_question:
              type: boolean
              description: Group transcript answers by expected question.
            template:
              type: string
              enum:
                - classic
                - modern
                - one_pager
              description: >-
                Report layout: classic, modern, or one_pager. Omit for the
                merchant default (modern when unset).
          description: >-
            Auto-generate a candidate PDF report with these options once the
            interview completes. null disables auto-export.
        interview_type:
          type: string
          nullable: true
          enum:
            - pre-screening
            - pre-screening-with-test-questions
            - second-interview
            - remote-freelancer-verification
            - strength-based-interview
            - potential-based-interview
            - process-verification-from-knowledge-base
          description: >-
            Interview style — configures the AI avatar and the follow-up
            questions it generates during the interview. Stored in
            creation_parameters; existing questions are NOT regenerated. Options
            — `pre-screening`: Pre-screening — quick qualification check
            focusing on basic requirements and availability. |
            `pre-screening-with-test-questions`: Pre-screening with test
            questions — pre-screening plus practical questions to test relevant
            skills. | `second-interview`: Second round interview — deeper dive
            for candidates who passed initial screening. |
            `remote-freelancer-verification`: Remote worker verification —
            verify remote work capabilities and communication skills. |
            `strength-based-interview`: Strength-based interview — focus on what
            candidates enjoy and excel at to predict job satisfaction. |
            `potential-based-interview`: Potential-based interview — assess
            learning ability and growth potential rather than past experience. |
            `process-verification-from-knowledge-base`: Knowledge Base interview
            — generate questions from your knowledge base documents..
          example: pre-screening-with-test-questions
        interview_tone:
          type: string
          nullable: true
          enum:
            - relaxed
            - simple
            - professional
            - persuasive
            - exact
          description: >-
            Tone — configures the AI avatar's speaking style and the follow-up
            questions it generates. Stored in creation_parameters; existing
            questions are NOT regenerated. Case-insensitive; omit to default to
            relaxed. Options — `relaxed`: Friendly and conversational tone that
            helps candidates feel at ease. | `simple`: Plain language at CEFR A2
            level — short sentences and simple words. | `professional`: Formal
            and business-like approach suitable for senior roles. |
            `persuasive`: Engaging style that encourages candidates to
            elaborate. | `exact`: Asks the questions exactly as provided,
            without rephrasing — for interviews built from your own questions
            (create_interview_from_questions) where the wording is a script..
          example: professional
        seniority_level:
          type: string
          nullable: true
          enum:
            - entry-level
            - intermediate
            - senior
            - managerial
            - director
            - executive
          description: >-
            Target seniority level for the role; auto-detected from the job
            description when omitted. Options — `entry-level`: Early-career or
            graduate roles. | `intermediate`: Some experience required. |
            `senior`: Experienced professional. | `managerial`: Team or
            department lead. | `director`: Director-level responsibility. |
            `executive`: C-suite or executive role..
          example: senior
        hiring_for_company:
          type: object
          nullable: true
          properties:
            name:
              type: string
              nullable: true
              description: >-
                End-employer name. Omit/null when hiring for yourself,
                'undisclosed' for an unnamed external client, or the client's
                company name.
              example: Unimo Enterprises
            description:
              type: string
              nullable: true
              description: >-
                Short description of the end employer, used as background
                context by the agent.
              example: >-
                Unimo Enterprises is a leading logistics and supply chain
                solutions provider.
            location:
              type: string
              nullable: true
              description: Primary location of the end employer.
              example: Sri Lanka
            sector:
              type: string
              nullable: true
              description: Industry / sector of the end employer.
              example: Logistics and Supply Chain
            company_size:
              type: string
              nullable: true
              description: Approximate headcount of the end employer.
              example: 100-200
          description: >-
            Who the position is really for. null (or an object with name
            null/blank) means hiring for yourself; { name: 'undisclosed' } for
            an unnamed external client; or { name: '<company>' } plus optional
            description/location/sector/company_size. Stored in
            creation_parameters.hiring_for_company.
          example:
            name: undisclosed
      required:
        - position_id
    JobInterviewUpdateResponse:
      type: object
      properties:
        position_id:
          type: string
          description: The id that was updated.
        is_multistage:
          type: boolean
          description: >-
            True when the id resolved to a multi-stage position
            (position_def_set) rather than a single interview.
        updated_fields:
          type: array
          items:
            type: string
          description: >-
            Names of the stored columns that were written, plus `status` when
            the lifecycle status was changed and `questions` when the question
            list was diffed.
          example:
            - name
            - tags
        questions_diff:
          $ref: '#/components/schemas/JobInterviewQuestionsDiff'
      required:
        - position_id
        - is_multistage
        - updated_fields
      description: Confirmation of what was updated.
    Error:
      type: object
      properties:
        error:
          type: string
          example: Field is required.
        name:
          type: string
          example: interview_result_id
      required:
        - error
    JobInterviewCreateFromArrayQuestion:
      type: object
      properties:
        question:
          type: string
          description: The question text shown to the candidate.
        id:
          type: string
          description: >-
            Identifier for this question. job-interview-get returns the
            question's real id here; send it back to job-interview-update so an
            unchanged question keeps its existing record (and with it its answer
            rules and any rendered avatar video). Also the handle another
            question references via conditional_question_main_id. On
            job-interview-create-from-array it is a caller-local value, only
            needed for those references.
        duration:
          type: number
          nullable: true
          description: Answer duration in seconds for this question.
        mojito_language_code:
          type: string
          nullable: true
          enum:
            - ar
            - bg
            - zh
            - hr
            - cs
            - da
            - nl
            - en
            - fil
            - fi
            - fr
            - de
            - el
            - hi
            - hu
            - id
            - it
            - ja
            - ko
            - ms
            - 'no'
            - pl
            - pt
            - br
            - ro
            - ru
            - sk
            - es
            - sv
            - ta
            - th
            - tr
            - uk
            - vi
          description: >-
            Per-question language override (one of the platform-languages.json
            codes). Inherits the interview language when omitted.
          example: en
        label:
          type: string
          nullable: true
          description: Optional label/tag stored on the question.
        is_conditional:
          type: boolean
          nullable: true
          description: >-
            Conditional follow-up question (view 'with listening conditional').
            Use with conditional_question_main_id.
        is_without_scoring:
          type: boolean
          nullable: true
          description: Question is asked but not scored (view 'without scoring').
        is_candidate_asking_recruiter:
          type: boolean
          nullable: true
          description: Candidate-asks-recruiter prompt (view 'candidate asking recruiter').
        is_expert:
          type: boolean
          nullable: true
          description: Expert listening question (view 'with listening expert').
        is_multiple_choice:
          type: boolean
          nullable: true
          description: Multiple-choice question (view 'multiple choice').
        question_alternatives:
          type: array
          nullable: true
          items:
            type: string
          description: Alternative phrasings for the question.
        conditional_question_main_id:
          type: string
          nullable: true
          description: >-
            For a conditional question, the id (the "id" field above) of the
            parent question in this same array that triggers it. The parent must
            appear earlier in the array than the conditional question
            referencing it.
        knowledge_base_id:
          type: string
          nullable: true
          description: Knowledge-base store id (uuid) the question draws context from.
        external_id:
          type: string
          nullable: true
          description: >-
            External identifier stored on the question. job-interview-update
            matches on this first, so an ATS that owns stable ids can send its
            own array and have the diff line up without round-tripping our ids.
        external_data:
          type: object
          nullable: true
          additionalProperties:
            nullable: true
          description: Arbitrary JSON metadata stored on the question.
        candidate_expectations_json:
          type: object
          nullable: true
          properties:
            weak:
              type: array
              items:
                type: string
              description: >-
                Baseline requirements every viable candidate should meet (table
                stakes).
            moderate:
              type: array
              items:
                type: string
              description: Requirements expected of a solid, competent candidate.
            strong:
              type: array
              items:
                type: string
              description: High-bar requirements only standout candidates clear.
          description: >-
            Per-question candidate expectations, bucketed by requirement level
            (weak/moderate/strong). Extra keys are preserved.
      required:
        - question
      additionalProperties:
        nullable: true
    JobInterviewQuestionsDiff:
      type: object
      properties:
        kept:
          type: array
          items:
            type: string
          description: Questions left exactly as they were, record and all.
        added:
          type: array
          items:
            type: string
          description: >-
            Ids of the questions created for entries that matched nothing
            stored.
        removed:
          type: array
          items:
            type: string
          description: >-
            Ids unlinked because no entry in the request matched them. The
            question records themselves still exist.
        replaced:
          type: array
          items:
            type: object
            properties:
              from:
                type: string
                description: The id that was unlinked.
              to:
                type: string
                description: The id of the question created in its place.
            required:
              - from
              - to
          description: >-
            Edited questions: the old record was unlinked and a new one created,
            so the change cannot leak into other interviews reusing it.
        question_ids:
          type: array
          items:
            type: string
          description: >-
            The interview's full ordered step list after the update, including
            the welcome / thank-you / instructional steps this endpoint does not
            manage.
        reactivated:
          type: boolean
          description: >-
            True when the interview was already active and was re-published so
            the new questions go live.
      required:
        - kept
        - added
        - removed
        - replaced
        - question_ids
        - reactivated
      description: >-
        What the question diff decided, question by question. Absent when
        `questions` was not sent.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Supabase JWT — `Authorization: Bearer <token>`.'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.