> ## 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.

# Change the settings of a position step

> Changes the name and settings of one step of a position: advance and kombo on every step, plus the one settings object of the step's type (meeting, certo, external_assessment, interview or pre_screening; another type's object is a 422). Only the keys sent change: nested keys are merged one by one, null removes a key. Works on published positions too (the structure is changed with set_position_process, drafts only). Settings are read live, so candidates already on the step get the new settings at once; nobody is e-mailed by this call. Use dry_run to see changed_keys, candidates_on_step, booked_meetings and warnings first, and expected_updated_at to refuse a stale change. Owners and recruiters on the position's access list; hiring managers read only.



## OpenAPI

````yaml https://cool.jobmojito.com/functions/v1/openapi post /merchant-position-step-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: Positions
    description: >-
      A position's hiring process: its steps and their settings, meeting slots,
      and copies of positions and interviews.
  - 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: Reports
    description: >-
      Custom reports: read the catalogue of datasets, build a report definition,
      check it, save it and run it.
  - name: Candidates
    description: List and manage candidates.
  - name: Tasks
    description: >-
      Follow-up tasks for the hiring team, about a candidate, an application or
      a position.
  - name: Document requests
    description: >-
      Ask candidates for documents (certificates, IDs, references), follow them
      up and mark them reviewed.
  - 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.
  - name: Feedback
    description: >-
      Send feature requests to the product team and report technical issues to
      support.
  - name: Integrations
    description: >-
      Ready-made connectors and how their fields map to JobMojito. A company
      sees the same tables under Integrations > Catalogue > Field mapping.


      ### ATS connector (Kombo)


      The applicant tracking system is connected through Kombo's unified ATS
      API. JobMojito keeps a copy of the ATS jobs, applications and candidates,
      links each position to one ATS job, invites applicants who reach the
      trigger stage, and writes the outcome back. Links, notes and attachments
      are written only when the company switched them on
      (merchant.kombo_selected_result_actions); job fields are not copied into
      the position.


      | JobMojito field | Direction | External field | Notes |

      | --- | --- | --- | --- |

      | `merchant.kombo_integration_id, merchant.kombo_integration_tool` | Into
      JobMojito | `integration-created / integration-deleted webhook: data.id,
      data.tool` | Set when the ATS connection is created and cleared when it is
      deleted. |

      | `kombo_jobs.id, kombo_jobs.name` | Into JobMojito | `GET /ats/jobs: id,
      name (fallback title)` | Copied on every full or incremental sync of the
      jobs. |

      | `kombo_jobs.status` | Into JobMojito | `jobs.status,
      jobs.remote_deleted_at` | DRAFT becomes draft, CLOSED or ARCHIVED becomes
      archived, deleted in the ATS becomes deleted. |

      | `kombo_jobs.data` | Into JobMojito | `jobs.* (whole job object)` | Kept
      as received; the position's own fields are not overwritten from it. |

      | `position_def_set.kombo_parameters.kombo_job_id,
      interview_def_set.kombo_parameters.kombo_job_id` | Into JobMojito |
      `jobs.id` | Links a position or interview to one ATS job, chosen by the
      recruiter. |

      | `position_def_set.status, interview_def_set.status` | Into JobMojito |
      `jobs.status (closed, archived, deleted, reopened)` | Closing the job in
      the ATS archives the linked positions and interviews; reopening it
      restores their previous status. |

      | `kombo_parameters.kombo_stage_id` | Into JobMojito | `jobs.stages[].id
      matched against applications.current_stage_id` | An application entering
      this stage triggers the invitation or the pre-screening; applicants
      already in it are invited when the position is published. |

      | `ATS pipeline report (stage names and order)` | Into JobMojito |
      `jobs.stages[].id, name, index` | Read for the ATS pipeline report only. |

      | `kombo_applications.id, kombo_job_id, kombo_candidate_id, data` | Into
      JobMojito | `GET /ats/applications: id, job_id, candidate_id` | Copied on
      application sync; applications of closed or archived jobs are not
      imported. |

      | `kombo_applications.kombo_stage_id` | Into JobMojito |
      `applications.current_stage_id` | A stage change re-runs the invitation
      check for that application. |

      | `kombo_applications.status` | Into JobMojito | `applications.outcome
      (HIRED, DECLINED), remote_deleted_at` | Hired, declined or deleted
      applications are archived and receive no further invitations. |

      | `position_result.outcome, interview_result.outcome` | Into JobMojito |
      `applications.outcome` | Set to hired or declined when the ATS marks the
      linked application, while the outcome is still pending. |

      | `position_result.status, interview_result.status` | Into JobMojito |
      `applications.remote_deleted_at` | An application deleted in the ATS
      archives the linked application in JobMojito if nobody has decided yet. |

      | `kombo_candidates.id, data, status` | Into JobMojito | `GET
      /ats/candidates: candidates.*, remote_deleted_at` | Copied on candidate
      sync; a candidate deleted in the ATS is archived. |

      | `profile_interview.email, profile_interview.email_auth` | Into JobMojito
      | `candidates.email_addresses[0].email_address` | Finds or creates the
      candidate when the application reaches the trigger stage. |

      | `profile_interview.name` | Into JobMojito | `candidates.first_name +
      last_name` | Set when the candidate is created from the ATS. |

      | `profile_interview.phone_number` | Into JobMojito |
      `candidates.phone_numbers[0].phone_number` | Set when the candidate is
      created from the ATS. |

      | `kombo_candidates.profile_interview_id` | Into JobMojito |
      `candidates.id (matched by e-mail)` | Links the ATS candidate to the
      JobMojito candidate on invitation or pre-screening. |

      | `interview_file (type resume)` | Into JobMojito | `GET
      /ats/applications/{id}/attachments, then /ats/candidates/{id}/attachments:
      type CV (fallback OTHER)` | The CV from the ATS is imported when the
      candidate is invited or pre-screened. |

      | `interview_result_pre_screening (AI pre-screening input)` | Into
      JobMojito | `applications.screening_question_answers[] (question.title,
      answer)` | The candidate's answers to the ATS screening questions are part
      of the AI pre-screening. |

      | `interview_result_pre_screening.nationality, residency` | Into JobMojito
      | `candidates.location.country (fallback address.country)` | Taken from
      the ATS candidate during pre-screening. |

      | `kombo_applications.interview_result_id,
      interview_result_pre_screening_id` | Into JobMojito | `applications.id` |
      Set when the candidate's result is linked back to the ATS application. |

      | `kombo_tags, kombo_rejection_reasons, kombo_users, kombo_offers,
      kombo_interviews` | Into JobMojito | `GET /ats/tags,
      /ats/rejection-reasons, /ats/users, /ats/offers, /ats/interviews` | Kept
      in sync so recruiters can pick tags and rejection reasons; the others are
      stored only. |

      | `kombo_parameters.kombo_selected_stage_id (step:
      config.kombo.accept_stage_id)` | From JobMojito | `PUT
      /ats/applications/{id}/stage` | Moves the application when the recruiter
      selects the candidate; the position's stage is used on the last step. |

      | `kombo_parameters.kombo_sync_all_results_stage_id` | From JobMojito |
      `PUT /ats/applications/{id}/stage` | Every processed result is moved to
      this stage, only when sync all results is on. |

      | `kombo_parameters.kombo_rejected_reason_human_id,
      kombo_rejected_reason_ai_id (step: config.kombo.reject_reason_id)` | From
      JobMojito | `POST /ats/applications/{id}/reject { rejection_reason_id,
      note }` | Rejects the application when the recruiter rejects; nothing is
      sent when no reason is configured. |

      | `Rejection note (result link, score, AI feedback)` | From JobMojito |
      `reject.note` | The note sent with the rejection. |

      | `interview_result result link + interview_result.score` | From JobMojito
      | `POST /ats/applications/{id}/result-links { label, url,
      details.attributes }` | Sent when result links are switched on: a signed
      link to the result with its score. |

      | `interview_result note (result link + score)` | From JobMojito | `POST
      /ats/applications/{id}/notes` | Sent when notes are switched on and the
      recruiter has decided, or sync all results is on. |

      | `interview_result.pdf_export_url (interview PDF report)` | From
      JobMojito | `POST /ats/applications/{id}/attachments (type OTHER)` | Sent
      when attachments are switched on; the PDF is generated first if missing. |

      | `interview_result_pre_screening score, recommendation and analysis` |
      From JobMojito | `POST /ats/applications/{id}/notes` | Sent after every AI
      pre-screening and again when the recruiter decides on it. |

      | `Pre-screening PDF report` | From JobMojito | `POST
      /ats/applications/{id}/attachments (type OTHER)` | Uploaded when
      attachments are switched on. |

      | `interview_result.coach_status (progress note)` | From JobMojito | `POST
      /ats/applications/{id}/notes` | A note when the interview fails or the
      answers are collected, only when sync all results is on. |

      | `position_result_step decision and recruiter notes (meeting step)` |
      From JobMojito | `POST notes, PUT stage, POST reject` | Sends '<step>:
      passed / failed' with the recruiter's notes, then moves or rejects. |

      | `human_interview_request reason and outcome` | From JobMojito | `POST
      notes, PUT stage, POST reject` | Notes the request, moves on pass and
      rejects on fail or decline. |

      | `merchant.kombo_tag_assignment.result_weak / result_moderate /
      result_strong / result_exceptional` | From JobMojito | `POST
      /ats/candidates/{id}/tags` | Score tags on result sync: under 4 weak,
      under 7 moderate, under 8.5 strong, up to 10 exceptional. |

      | `merchant.kombo_tag_assignment.interview_selected / interview_rejected`
      | From JobMojito | `POST /ats/candidates/{id}/tags` | Decision tags on a
      recruiter decision; the selected tag only on the last step. |

      | `merchant.kombo_sync (manual sync)` | From JobMojito | `POST
      /force-sync` | Asks Kombo to sync the ATS again when the recruiter presses
      sync. |


      ### Webhooks


      JobMojito POSTs the same JSON payload for the events interview_result (the
      result is final and scored, sent again when a watched field changes),
      interview_collected (the candidate finished, before scoring) and
      interview_failed (failed, abandoned or no speech). Configure the URL,
      events and authentication headers per environment under Integrations >
      Custom integration; failed deliveries are retried and kept in the delivery
      history.


      | JobMojito field | Direction | External field | Notes |

      | --- | --- | --- | --- |

      | `interview_result.id` | From JobMojito | `id` | The result the event is
      about. |

      | `interview_result.question_set_id (interview_def_set.id)` | From
      JobMojito | `interview_id` | The interview definition. |

      | `interview_result.question_set_id (interview_def_set.id)` | From
      JobMojito | `question_set_id` | Same value as interview_id. |

      | `interview_result.status` | From JobMojito | `status` | active for
      interview_result, draft for the other two events. |

      | `interview_result.coach_status` | From JobMojito | `interview_status` |
      completed, failed, abandoned and so on. |

      | `interview_result.processing_status` | From JobMojito |
      `processing_status` | AI processing state. |

      | `interview_result.profile_interview_id` | From JobMojito |
      `profile_interview_id` | The candidate. |

      | `interview_result.profile_id` | From JobMojito | `profile_id` | The
      candidate's portal account, when there is one. |

      | `profile_interview.external_id` | From JobMojito |
      `candidate_external_id` | Your id for the candidate; present when a
      candidate is linked. |

      | `profile_interview.name` | From JobMojito | `candidate_name` | Present
      when a candidate is linked. |

      | `profile_interview.email` | From JobMojito | `candidate_email` | Present
      when a candidate is linked. |

      | `profile_interview.phone_number` | From JobMojito |
      `candidate_phone_number` | Present when a candidate is linked. |

      | `interview_result.recruiter_go_next_round` | From JobMojito |
      `recruiter_go_next_round` | The recruiter's decision; usually empty in
      interview_collected and interview_failed. |

      | `interview_result.ai_analysis` | From JobMojito | `ai_analysis` |
      Candidate-facing analysis, filled in interview_result. |

      | `interview_result.ai_analysis_recruiter` | From JobMojito |
      `ai_analysis_recruiter` | Recruiter-facing analysis, filled in
      interview_result. |

      | `interview_result.ai_analysis_other` | From JobMojito |
      `ai_analysis_other` | Session analyses by name, for example
      strengths_concerns. |

      | `interview_result.ai_analysis_other.strengths_concerns.strengths` | From
      JobMojito | `ai_analysis_recruiter_why_hire` | Deprecated copy kept for
      existing integrations. |

      | `interview_result.ai_analysis_other.strengths_concerns.concerns` | From
      JobMojito | `ai_analysis_recruiter_why_not_hire` | Deprecated copy kept
      for existing integrations. |

      | `interview_result.score_interview_ai` | From JobMojito |
      `ai_analysis_recruiter_score` | Recruiter-facing AI score, filled in
      interview_result. |

      | `interview_result.score` | From JobMojito | `score` | Overall score,
      filled in interview_result. |

      | `interview_result.pdf_export_url` | From JobMojito | `pdf_export_url` |
      When a PDF report is configured, interview_result waits until the PDF
      exists. |

      | `Changed fields of the result` | From JobMojito | `reason` | Which
      watched fields changed; 'manual re-trigger of ...' on a resend from the
      delivery history. |
paths:
  /merchant-position-step-update:
    post:
      tags:
        - Positions
      summary: Change the settings of a position step
      description: >-
        Changes the name and settings of one step of a position: advance and
        kombo on every step, plus the one settings object of the step's type
        (meeting, certo, external_assessment, interview or pre_screening;
        another type's object is a 422). Only the keys sent change: nested keys
        are merged one by one, null removes a key. Works on published positions
        too (the structure is changed with set_position_process, drafts only).
        Settings are read live, so candidates already on the step get the new
        settings at once; nobody is e-mailed by this call. Use dry_run to see
        changed_keys, candidates_on_step, booked_meetings and warnings first,
        and expected_updated_at to refuse a stale change. Owners and recruiters
        on the position's access list; hiring managers read only.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PositionStepUpdateRequest'
      responses:
        '200':
          description: The step after the change (or as it would be, in a dry run).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PositionStepUpdateResult'
        '401':
          description: Missing, expired or invalid access token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Not company staff, a hiring manager (read only), another company, or
            a merchant switch is off (meeting_panels for a panel,
            meeting_email_variants for an e-mail version; the message names it).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: No such step, or its position is not visible to you.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: >-
            expected_updated_at is not the step's current version: someone
            changed it since you read it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: >-
            Validation error naming the field or setting: a settings object of
            another step type, an unknown key, a value out of range, a provider,
            form or user not of this company, or nothing to change.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    PositionStepUpdateRequest:
      type: object
      properties:
        step_id:
          type: string
          format: uuid
          description: >-
            The step (position_def_step.id, from get_interview_definition with
            include=process or set_position_process).
        name:
          type: string
          nullable: true
          maxLength: 300
          description: >-
            New name of the step. null or empty removes the name (the type's
            default label is shown); left out keeps it.
        expected_updated_at:
          type: string
          nullable: true
          format: date-time
          description: >-
            The step's updated_at as you read it (get_interview_definition with
            include=process, or an earlier answer of this call). When the step
            changed since, nothing is written and the answer is 409; read it
            again and retry. null or left out: not checked.
        dry_run:
          type: boolean
          default: false
          description: >-
            true: validate and answer what would change and whom it reaches,
            without writing anything.
        advance:
          type: string
          nullable: true
          enum:
            - auto
            - manual
          description: >-
            auto: a candidate who passes moves on by themselves; manual: a
            recruiter moves them on. null = auto.
        kombo:
          $ref: '#/components/schemas/PositionStepKombo'
        meeting:
          $ref: '#/components/schemas/PositionStepMeeting'
        certo:
          $ref: '#/components/schemas/PositionStepCerto'
        external_assessment:
          $ref: '#/components/schemas/PositionStepExternalAssessment'
        interview:
          $ref: '#/components/schemas/PositionStepInterview'
        pre_screening:
          type: object
          properties:
            type:
              type: string
              enum:
                - resume
                - form
                - resume_with_form
              description: 'What the candidate sends: resume, form, or resume_with_form.'
            form_fields:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                required:
                  - id
              maxItems: 100
              description: >-
                The whole list of form fields (replaced, not merged), each with
                its own id: standard fields reuse the rule id (e.g.
                form_education, with mandatory), custom fields use
                custom_<timestamp> with title, field_type (text, file, radio),
                type (required, optional) and, for radio, options (a list of
                strings), e.g. {"id": "custom_1731100000000", "title": "Do you
                have a work permit?", "field_type": "radio", "type": "required",
                "options": ["Yes", "No"]}. A screening rule on it
                (assessment_rules) is optional.
            assessment_rules:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: string
                    minLength: 1
                required:
                  - id
              maxItems: 100
              description: >-
                The whole list of rules (replaced, not merged), each with its
                own id: resume_match (resume_score_accept / resume_score_reject,
                whole numbers 0 to 10), resume_technical_experience, form_*
                rules with type screening, required or optional and action
                reject or mark_for_review.
            position_country:
              type: string
              pattern: ^[A-Za-z]{2}$
              description: ISO country code of the position; stored upper case.
            candidate_expectations:
              type: string
              nullable: true
              maxLength: 4000
              description: >-
                What the AI expects of a candidate, in words. null or empty
                removes it.
            all_rules_fulfilled_auto_approve:
              type: boolean
              description: >-
                true: when every rule is fulfilled the pre-screening is approved
                without a recruiter's review. Whether the approved candidate
                then moves to the next step by themselves is `advance` (auto) or
                a recruiter's move (manual).
            id:
              type: string
              description: Read only (as job-interview-get answers it); ignored.
            status:
              type: string
              description: Read only (as job-interview-get answers it); ignored.
          additionalProperties: false
          description: >-
            Pre-screening steps: the settings to change, as include=process
            returns them; that object can be sent back as it is.
      required:
        - step_id
      additionalProperties: false
    PositionStepUpdateResult:
      type: object
      properties:
        step:
          $ref: '#/components/schemas/PositionStep'
        changed_keys:
          type: array
          items:
            type: string
          description: >-
            What changed (or would change in a dry run), as paths: name,
            advance, kombo.accept_stage_id, meeting.duration_minutes,
            external_assessment.due_days, scope_types, allow_human_interview,
            pre_screening.type, ...
        candidates_on_step:
          type: integer
          description: >-
            Applications whose current step is this step (not withdrawn, hired
            or declined). Settings are read live: a change reaches them at once.
        booked_meetings:
          type: integer
          description: Upcoming booked meetings on this step's slots.
        warnings:
          type: array
          items:
            type: string
          description: >-
            Things to tell the user before or after the change (who it reaches,
            settings that have no effect yet).
        dry_run:
          type: boolean
          description: true when nothing was written.
      required:
        - step
        - changed_keys
        - candidates_on_step
        - booked_meetings
        - warnings
        - dry_run
    Error:
      type: object
      properties:
        error:
          type: string
          example: Field is required.
        name:
          type: string
          example: interview_result_id
      required:
        - error
    PositionStepKombo:
      type: object
      properties:
        accept_stage_id:
          type: string
          nullable: true
          maxLength: 200
          description: >-
            ATS stage (Kombo id) a candidate moves to when accepted on this
            step. null removes the setting (its default applies again); left out
            keeps it.
        reject_reason_id:
          type: string
          nullable: true
          maxLength: 200
          description: >-
            ATS rejection reason (Kombo id) used when a recruiter rejects on
            this step. null removes the setting (its default applies again);
            left out keeps it.
        reject_reason_ai_id:
          type: string
          nullable: true
          maxLength: 200
          description: >-
            ATS rejection reason (Kombo id) used when the AI rejects on this
            step. null removes the setting (its default applies again); left out
            keeps it.
      additionalProperties: false
      description: >-
        Mapping of this step to the connected ATS (Kombo). Each key is merged
        separately.
    PositionStepMeeting:
      type: object
      properties:
        mode:
          type: string
          nullable: true
          enum:
            - slots
            - availability
          description: >-
            How candidates book: slots (hand-made slots, the default; add them
            with manage_meeting_slot) or availability (free times of the
            interviewers). null removes the setting (its default applies again);
            left out keeps it.
        duration_minutes:
          type: integer
          nullable: true
          minimum: 5
          maximum: 1440
          description: >-
            Meeting length in minutes, 5 to 1440 (default 30). null removes the
            setting (its default applies again); left out keeps it.
        location:
          type: string
          nullable: true
          maxLength: 500
          description: >-
            Address or room shown to the candidate when a slot has none. null
            removes the setting (its default applies again); left out keeps it.
        conference_provider:
          type: string
          nullable: true
          enum:
            - in_person
            - fixed
            - zoom
            - teams
            - meet
          description: >-
            The meeting link: in_person (no link), fixed (meeting_url), zoom /
            teams / meet (made at booking with the interviewer's own calendar
            account, meeting_url is the fallback). Absent: fixed when
            meeting_url is set, else in_person. null removes the setting (its
            default applies again); left out keeps it.
        meeting_url:
          type: string
          nullable: true
          maxLength: 2000
          pattern: ^https?:\/\/\S+$
          description: >-
            Video link (http or https) used when a slot has none. null removes
            the setting (its default applies again); left out keeps it.
        instructions:
          type: string
          nullable: true
          maxLength: 4000
          description: >-
            Instructions shown to the candidate. null removes the setting (its
            default applies again); left out keeps it.
        reschedule_cutoff_hours:
          type: integer
          nullable: true
          minimum: 0
          maximum: 8760
          description: >-
            Hours before the meeting after which the candidate can no longer
            reschedule or cancel (default 24). null removes the setting (its
            default applies again); left out keeps it.
        nudge_after_days:
          type: integer
          nullable: true
          minimum: 0
          maximum: 365
          description: >-
            Days after which a candidate who has not booked gets a reminder; 0 =
            never (default 3). null removes the setting (its default applies
            again); left out keeps it.
        interviewer_profile_ids:
          type: array
          nullable: true
          items:
            type: string
            format: uuid
          maxItems: 50
          description: >-
            Availability mode: the interviewers whose free times are offered
            (profile.id of users of the company); empty = the position's
            recruiter. null removes the setting (its default applies again);
            left out keeps it.
        panel_profile_ids:
          type: array
          nullable: true
          items:
            type: string
            format: uuid
          minItems: 2
          maxItems: 8
          description: >-
            Availability mode, company feature meeting_panels: a panel of 2 to 8
            users who all attend (profile.id); the first leads the meeting and
            cannot be a read-only user. Candidates are offered only times when
            everyone is free. null = one interviewer. null removes the setting
            (its default applies again); left out keeps it.
        slot_interval_minutes:
          type: integer
          nullable: true
          minimum: 5
          maximum: 240
          description: >-
            Availability mode: start times every N minutes, 5 to 240 (default
            30). null removes the setting (its default applies again); left out
            keeps it.
        min_notice_hours:
          type: integer
          nullable: true
          minimum: 0
          maximum: 720
          description: >-
            Availability mode: earliest booking, hours from now, 0 to 720
            (default 12). null removes the setting (its default applies again);
            left out keeps it.
        horizon_days:
          type: integer
          nullable: true
          minimum: 1
          maximum: 365
          description: >-
            Availability mode: latest booking, days from now, 1 to 365 (default
            21). null removes the setting (its default applies again); left out
            keeps it.
        data_collection:
          type: object
          nullable: true
          properties:
            mode:
              type: string
              enum:
                - none
                - form
                - text
              description: none, form (a meeting form, taxonomy_id) or text (free notes).
            taxonomy_id:
              type: string
              nullable: true
              format: uuid
              description: >-
                A meeting form of this company, made in the admin (the current
                one is in job-interview-get include=process); required for mode
                form.
          required:
            - mode
          additionalProperties: false
          description: >-
            What the interviewer records after the meeting. Replaced as a whole.
            null removes the setting (its default applies again); left out keeps
            it.
        email_variant:
          type: string
          nullable: true
          maxLength: 100
          description: >-
            Needs the meeting_email_variants feature: the name of the e-mail
            version used for this step's meeting e-mails. null removes the
            setting (its default applies again); left out keeps it.
      additionalProperties: false
      description: >-
        Settings of a meeting step. Each key is merged separately; keys left out
        keep their value.
    PositionStepCerto:
      type: object
      properties:
        wait_for_identity:
          type: boolean
          description: >-
            Wait until the candidate has verified their identity before the step
            completes.
        include_contact:
          type: boolean
          description: Ask for the contact details of referees.
        scope_types:
          type: array
          nullable: true
          items:
            type: string
            enum:
              - employment
              - education
              - certification
              - role
              - language
              - right_to_work
          minItems: 1
          description: What is verified; null = everything.
      additionalProperties: false
      description: Settings of a certo.bio verification step.
    PositionStepExternalAssessment:
      type: object
      properties:
        provider_id:
          type: string
          format: uuid
          description: >-
            An active assessment provider of this company, set up in the admin
            (a step's current one is in job-interview-get include=process).
            Required on a new step.
        instructions:
          type: string
          nullable: true
          maxLength: 3000
          description: >-
            Shown to the candidate (falls back to the provider's instructions).
            null removes the setting (its default applies again); left out keeps
            it.
        due_days:
          type: integer
          minimum: 1
          maximum: 60
          description: Days the candidate has to finish, 1 to 60 (default 7).
        pass_score:
          type: number
          nullable: true
          description: >-
            Optional pass mark: a result without a pass flag passes when its
            score is at least this. null removes the setting (its default
            applies again); left out keeps it.
      additionalProperties: false
      description: >-
        Settings of an external assessment step (the external_assessment
        feature).
    PositionStepInterview:
      type: object
      properties:
        allow_human_interview:
          type: boolean
          description: >-
            Let candidates ask for an interview with a person instead of the AI.
            Question content is changed with update_interview, on the step's
            interview_set_id.
      additionalProperties: false
      description: Settings of an AI interview step.
    PositionStep:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The step (position_def_step.id).
        type:
          type: string
          enum:
            - pre-screening
            - interview
            - meeting
            - external_assessment
            - certo_verification
          description: >-
            Step type: pre-screening, interview (AI interview), meeting,
            external_assessment or certo_verification.
        name:
          type: string
          nullable: true
          description: The name recruiters gave the step; null = the type's default label.
        position_id:
          type: string
          format: uuid
          description: The position (position_def_set.id).
        sequence_no:
          type: number
          description: Place in the process, 1 = first.
        updated_at:
          type: string
          description: >-
            Version of the step (when it last changed, else when it was made).
            Send it back as expected_updated_at to refuse a change made by
            someone else in the meantime.
        interview_set_id:
          type: string
          format: uuid
          description: >-
            AI interview steps: the interview (interview_def_set.id); its
            questions are changed with update_interview.
        interview_pre_screening_id:
          type: string
          format: uuid
          description: 'Pre-screening steps: interview_def_pre_screening.id.'
        advance:
          type: string
          enum:
            - auto
            - manual
          description: auto or manual (see the request field).
        kombo:
          $ref: '#/components/schemas/PositionStepKombo'
        meeting:
          $ref: '#/components/schemas/PositionStepMeeting'
        certo:
          type: object
          properties:
            wait_for_identity:
              type: boolean
              description: See the request field.
            include_contact:
              type: boolean
              description: See the request field.
            scope_types:
              type: array
              nullable: true
              items:
                type: string
                enum:
                  - employment
                  - education
                  - certification
                  - role
                  - language
                  - right_to_work
              description: null = everything.
          required:
            - wait_for_identity
            - include_contact
            - scope_types
          description: certo_verification steps.
        external_assessment:
          $ref: '#/components/schemas/PositionStepExternalAssessment'
        interview:
          $ref: '#/components/schemas/PositionStepInterview'
        pre_screening:
          $ref: '#/components/schemas/PositionStepPreScreening'
      required:
        - id
        - type
        - name
        - position_id
        - sequence_no
        - updated_at
        - advance
      description: >-
        A step of a position's process with its settings; only the settings
        object of the step's own type is present.
    PositionStepPreScreening:
      type: object
      properties:
        type:
          type: string
          enum:
            - resume
            - form
            - resume_with_form
          description: 'What the candidate sends: resume, form, or resume_with_form.'
        form_fields:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
            required:
              - id
          maxItems: 100
          description: >-
            The whole list of form fields (replaced, not merged), each with its
            own id: standard fields reuse the rule id (e.g. form_education, with
            mandatory), custom fields use custom_<timestamp> with title,
            field_type (text, file, radio), type (required, optional) and, for
            radio, options (a list of strings), e.g. {"id":
            "custom_1731100000000", "title": "Do you have a work permit?",
            "field_type": "radio", "type": "required", "options": ["Yes",
            "No"]}. A screening rule on it (assessment_rules) is optional.
        assessment_rules:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                minLength: 1
            required:
              - id
          maxItems: 100
          description: >-
            The whole list of rules (replaced, not merged), each with its own
            id: resume_match (resume_score_accept / resume_score_reject, whole
            numbers 0 to 10), resume_technical_experience, form_* rules with
            type screening, required or optional and action reject or
            mark_for_review.
        position_country:
          type: string
          pattern: ^[A-Za-z]{2}$
          description: ISO country code of the position; stored upper case.
        candidate_expectations:
          type: string
          nullable: true
          maxLength: 4000
          description: >-
            What the AI expects of a candidate, in words. null or empty removes
            it.
        all_rules_fulfilled_auto_approve:
          type: boolean
          description: >-
            true: when every rule is fulfilled the pre-screening is approved
            without a recruiter's review. Whether the approved candidate then
            moves to the next step by themselves is `advance` (auto) or a
            recruiter's move (manual).
      additionalProperties: false
      description: Settings of the pre-screening step.
  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.