{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/jobmojito-com/json-schema/jobmojito-com-job-interview-create-from-array-request-schema.json",
  "title": "JobInterviewCreateFromArrayRequest",
  "x-generated": "2026-11-13",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/jobmojito-com-openapi.json#/components/schemas/JobInterviewCreateFromArrayRequest",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "description": "Interview/position name."
    },
    "location": {
      "type": "string",
      "minLength": 1,
      "description": "Job location — a city/country, or `remote`. Required and must not be empty: when the job description gives no location, pass `Not specified`."
    },
    "interview_template_id": {
      "type": "string",
      "minLength": 1,
      "description": "Id of the interview template to use. An id from merchant-avatar-list."
    },
    "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": "Platform language code (one of the listed codes); must also resolve to a supported language with an Azure speech mapping."
    },
    "description": {
      "type": "string",
      "minLength": 1,
      "description": "Short interview description."
    },
    "status": {
      "type": "string",
      "enum": [
        "draft",
        "active"
      ],
      "description": "Lifecycle status of the interview. Options — `draft`: Created but not published — not visible to candidates and cannot be run yet. Use to stage an interview before going live. | `active`: Published and live — candidates can run it."
    },
    "type": {
      "type": "string",
      "enum": [
        "interview",
        "coaching",
        "assessment"
      ],
      "description": "Product type of the interview. Options — `interview`: Standard candidate interview for a role — answers are AI-scored as input for the reviewer's decision. | `coaching`: Practice/coaching session — candidate-facing feedback to help them improve; not a hiring evaluation. Only available on the coaching portal, NOT the interview portal. | `assessment`: Skills/knowledge assessment — evaluates competencies and is scored like an interview."
    },
    "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."
    },
    "questions": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/JobInterviewCreateFromArrayQuestion"
      },
      "minItems": 1,
      "description": "Ordered list of interview questions to create as steps."
    },
    "recording": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "audio_first_5_answers",
        "audio_all",
        "video_all",
        "video_first_5_answers",
        "none"
      ],
      "description": "Cheating/proctoring detection mode for candidate answers — this is NOT a full session recording. Video options also record the candidate. Omit, null or `none` 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. | `none`: No cheating detection."
    },
    "recording_full_session": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "audio_all",
        "video_all",
        "none"
      ],
      "description": "Full interview-session recording (includes the avatar and voice) produced as a single file. Independent of `recording`. Omit, null or `none` 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. | `none`: No full-session recording."
    },
    "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."
    },
    "interview_type": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "pre-screening",
        "pre-screening-with-test-questions",
        "second-interview",
        "remote-freelancer-verification",
        "strength-based-interview",
        "potential-based-interview",
        "process-verification-from-knowledge-base",
        "knockout-screening"
      ],
      "description": "Interview style — configures the AI avatar and the follow-up questions it generates during the interview. The base `questions` you supply are used as-is and are NOT affected by this setting. 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. | `knockout-screening`: Knock-out screening — a short (about 5 minute) check of the role's must-haves with closed questions; ends early, politely, when a must-have is clearly not met. On creation it defaults custom_scoring.early_stop to true (where the avatar supports early stop) and max_followups to 1 unless you send them."
    },
    "seniority_level": {
      "type": [
        "string",
        "null"
      ],
      "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."
    },
    "result_view": {
      "type": [
        "string",
        "null"
      ],
      "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."
    },
    "interview_conversation_speed": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "slower",
        "normal",
        "faster",
        "fluent"
      ],
      "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. | `fluent`: Talking pace: the avatar answers 300 ms after the candidate stops speaking. A pause mid-sentence also ends their turn."
    },
    "candidate_video_introduction": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "optional",
        "required"
      ],
      "description": "Whether a candidate video introduction is optional or required."
    },
    "interview_tone": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "relaxed",
        "simple",
        "professional",
        "persuasive",
        "exact"
      ],
      "description": "Tone — configures the AI avatar's speaking style and the follow-up questions it generates; the base `questions` you supply are not affected. 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 where the wording is a script."
    },
    "interview_attempts": {
      "type": [
        "number",
        "null"
      ],
      "description": "Allowed attempts, 1-20."
    },
    "questions_random_subset": {
      "type": [
        "number",
        "null"
      ],
      "description": "Fraction of questions to randomly ask, between 0.01 and 0.9."
    },
    "max_followups": {
      "type": [
        "integer",
        "null"
      ],
      "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)."
    },
    "code": {
      "type": [
        "string",
        "null"
      ],
      "description": "Optional external code/reference."
    },
    "cover_image_url": {
      "type": [
        "string",
        "null"
      ],
      "description": "Cover image URL."
    },
    "interview_department": {
      "type": [
        "string",
        "null"
      ],
      "description": "Department the position belongs to."
    },
    "interview_salary": {
      "type": [
        "string",
        "null"
      ],
      "description": "Salary range shown for the position."
    },
    "interview_available_till": {
      "type": [
        "string",
        "null"
      ],
      "description": "ISO date/time after which the interview is no longer available to candidates. null keeps it always available."
    },
    "recruiter_profile_id": {
      "type": [
        "string",
        "null"
      ],
      "description": "Profile id of the recruiter owning this interview. A user of the company who is not read only: an owner, recruiter or admin from merchant-user-list."
    },
    "hiring_for_company": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "name": {
          "type": [
            "string",
            "null"
          ],
          "description": "End-employer name. Omit/null when hiring for yourself, 'undisclosed' for an unnamed external client, or the client's company name."
        },
        "description": {
          "type": [
            "string",
            "null"
          ],
          "description": "Short description of the end employer, used as background context by the agent."
        },
        "location": {
          "type": [
            "string",
            "null"
          ],
          "description": "Primary location of the end employer."
        },
        "sector": {
          "type": [
            "string",
            "null"
          ],
          "description": "Industry / sector of the end employer."
        },
        "company_size": {
          "type": [
            "string",
            "null"
          ],
          "description": "Approximate headcount of the end employer."
        }
      },
      "description": "Who the position is really for. Omit/null (or an object with name null/blank) when hiring for yourself; { name: 'undisclosed' } for an unnamed external client; or { name: '<company>' } plus optional description/location/sector/company_size for a named client. Stored in creation_parameters.hiring_for_company."
    },
    "tags": {
      "type": [
        "array",
        "null"
      ],
      "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 `merchant_public` (or the platform's own `public`) are listed."
    },
    "required_pronunciation": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "Require pronunciation assessment (restricts to pronunciation-capable languages). Defaults to false."
    },
    "result_enable_edit_transcript": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "Allow editing the transcript on the result view. Defaults to true."
    },
    "pdf_export_auto_config": {
      "type": [
        "object",
        "null"
      ],
      "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 (one of the listed codes)."
        },
        "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."
    },
    "knowledge_base_store_id": {
      "type": [
        "string",
        "null"
      ],
      "format": "uuid",
      "description": "Optional knowledge base store id; validated for existence."
    },
    "merchant_id": {
      "type": [
        "string",
        "null"
      ],
      "description": "Target merchant id (admins / sub-merchant only)."
    },
    "description_long": {
      "type": [
        "string",
        "null"
      ],
      "description": "Long-form interview description. 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"
    },
    "candidate_expectations": {
      "type": [
        "string",
        "null"
      ],
      "description": "Free-text candidate expectations."
    },
    "candidate_expectations_json": {
      "type": [
        "object",
        "null"
      ],
      "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": "Pre-generated candidate expectations, bucketed by requirement level (weak/moderate/strong); auto-generated when omitted for type=interview. Extra keys are preserved."
    },
    "custom_scoring": {
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": {
        "nullable": true
      },
      "description": "Custom scoring overrides merged with defaults."
    },
    "additional_context": {
      "type": [
        "object",
        "null"
      ],
      "additionalProperties": {
        "nullable": true
      },
      "description": "Extra context forwarded to expectation generation."
    },
    "instructional_video": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "Enable an instructional video before approval."
    },
    "instructional_video_custom_text": {
      "type": [
        "string",
        "null"
      ],
      "description": "Custom text for the instructional video."
    },
    "disable_deduplication": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "When true, skip step deduplication on insert."
    },
    "welcome_message": {
      "type": [
        "string",
        "null"
      ],
      "description": "Custom welcome message."
    },
    "thank_you_message": {
      "type": [
        "string",
        "null"
      ],
      "description": "Custom thank-you message."
    },
    "microphone_test_message": {
      "type": [
        "string",
        "null"
      ],
      "description": "Custom microphone-test instruction for a recorded (offline avatar) interview, spoken by the avatar and shown on screen before the first question. Omitted uses the default prompt in the interview language."
    },
    "microphone_test_no_speech_message": {
      "type": [
        "string",
        "null"
      ],
      "description": "Custom text shown when the microphone test hears nothing. Omitted uses the default text in the candidate's language."
    },
    "is_embedded": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "Set true when the interview will be embedded as an iframe on an external page. Creates an embed key and returns embed_id/embed_signing_key, used to authenticate/sign the iframe embed."
    },
    "interview_category": {
      "type": [
        "string",
        "null"
      ],
      "description": "Job category shown on public listings, above the department (free text, e.g. \"Ashore\"). Blank is stored as null."
    },
    "country_availability": {
      "type": [
        "object",
        "null"
      ],
      "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)."
        },
        "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."
        },
        "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 (personal invitation links) and candidates who already started keep access; API and MCP calls themselves are never restricted. Null = not used, every country."
    },
    "candidate_notification_channel": {
      "type": [
        "string",
        "null"
      ],
      "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."
    }
  },
  "required": [
    "name",
    "location",
    "interview_template_id",
    "mojito_language_code",
    "description",
    "status",
    "type",
    "visibility",
    "questions"
  ],
  "$defs": {
    "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",
            "null"
          ],
          "description": "Answer duration in seconds for this question."
        },
        "mojito_language_code": {
          "type": [
            "string",
            "null"
          ],
          "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 listed codes). Inherits the interview language when omitted."
        },
        "label": {
          "type": [
            "string",
            "null"
          ],
          "description": "Optional label/tag stored on the question."
        },
        "is_conditional": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "A yes/no question that decides which follow-ups are asked (view 'with listening conditional'). Its follow-ups point at it with conditional_question_main_id."
        },
        "is_without_scoring": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Question is asked but not scored (view 'without scoring')."
        },
        "is_candidate_asking_recruiter": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Candidate-asks-recruiter prompt (view 'candidate asking recruiter')."
        },
        "is_expert": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Expert listening question (view 'with listening expert')."
        },
        "is_multiple_choice": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Multiple-choice question (view 'multiple choice')."
        },
        "question_alternatives": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          },
          "description": "Alternative phrasings for the question."
        },
        "conditional_question_main_id": {
          "type": [
            "string",
            "null"
          ],
          "description": "For a follow-up question, the id (the \"id\" field above) of the yes/no question (is_conditional) in this same array that decides whether it is asked. The yes/no question must appear earlier in the array. Use conditional_question_answer to choose the answer that shows it."
        },
        "conditional_question_answer": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "With conditional_question_main_id: the answer to the yes/no question that shows this follow-up. `true` (the default) asks it after a yes, `false` after a no, so each answer can lead to its own follow-ups. Ignored on a question without conditional_question_main_id."
        },
        "is_skippable": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "The candidate may skip this question: the recorded (offline avatar) interview shows a Skip button on it, and a skipped question is saved without an answer. Defaults to false."
        },
        "knowledge_base_id": {
          "type": [
            "string",
            "null"
          ],
          "description": "Knowledge-base store id (uuid) the question draws context from."
        },
        "external_id": {
          "type": [
            "string",
            "null"
          ],
          "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",
            "null"
          ],
          "additionalProperties": {
            "nullable": true
          },
          "description": "Arbitrary JSON metadata stored on the question."
        },
        "candidate_expectations_json": {
          "type": [
            "object",
            "null"
          ],
          "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
      }
    }
  }
}