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

# Create Study

> Validate a study guide and create a draft study in your organization



## OpenAPI

````yaml api-v2/openapi.yaml POST /api/public/v1/studies/create
openapi: 3.0.3
info:
  title: Listen Labs Public API v2
  version: 2.0.0
  description: >-
    Create and launch studies, and retrieve response data programmatically.
    Authenticated with an `x-api-key` header; the key is scoped to a single
    organization.


    Cross-field rules that JSON Schema cannot express (screening placement,
    min/maxSelect coupling, unique externalIds, reference resolution,
    exclusiveOption placement) are described on the relevant schemas and
    enforced by the server (returned as 400 responses).


    All error responses share one JSON envelope: `error` (human-readable
    message, may change) and `code` (stable machine-readable identifier; branch
    on this). 400 responses may also carry `issues` with per-field schema
    violations. The possible codes for each response are listed in its
    description.
servers:
  - url: https://listenlabs.ai
    description: Production
security:
  - ApiKeyAuth: []
paths:
  /api/public/v1/studies/create:
    post:
      summary: Create a study (draft) from a guide
      description: Validates the guide and creates a draft study in the API key's org.
      operationId: createStudy
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateStudyRequest'
      responses:
        '201':
          description: Draft created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateResponse'
        '400':
          description: >-
            Invalid JSON, request body, or study guide. Codes: `invalid_json`,
            `invalid_request_body`, `invalid_study_guide`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
              examples:
                invalidJson:
                  value:
                    error: Invalid JSON body
                    code: invalid_json
                invalidRequestBody:
                  value:
                    error: Invalid request body
                    code: invalid_request_body
                    issues:
                      - code: invalid_type
                        expected: string
                        received: undefined
                        path:
                          - title
                        message: Required
                invalidStudyGuide:
                  value:
                    error: >-
                      Invalid study guide: conditional references unknown item
                      externalId 'q2'
                    code: invalid_study_guide
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: >-
            The draft was modified concurrently; retry. Codes:
            `concurrent_modification`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                concurrentModification:
                  value:
                    error: Study was modified concurrently; please retry
                    code: concurrent_modification
        '500':
          $ref: '#/components/responses/ServerError'
components:
  schemas:
    CreateStudyRequest:
      type: object
      properties:
        title:
          type: string
          minLength: 1
        externalTitle:
          type: string
        background:
          type: string
        studyGoal:
          type: string
        config:
          $ref: '#/components/schemas/Config'
        welcomeMessage:
          $ref: '#/components/schemas/WelcomeMessage'
        closingMessage:
          type: string
        studyGuide:
          type: array
          items:
            $ref: '#/components/schemas/Block'
          minItems: 1
      required:
        - title
        - studyGuide
      additionalProperties: false
      description: >-
        Rules enforced by the server: at most one screening block and it must be
        first; screening blocks may contain only multiple_choice items and every
        option must carry a status; concept blocks require conceptSamplingConfig
        (>=1 concept) and other blocks must omit it; externalIds must be unique
        across blocks, items, options, and concepts; conditional questionId and
        carryForwardFrom must reference the externalId of an earlier item;
        concept conditionals must reference an item in a block before the
        concept block.
    CreateResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
        linkId:
          type: string
        status:
          type: string
          enum:
            - draft
      required:
        - id
        - linkId
        - status
      additionalProperties: false
    ValidationError:
      type: object
      properties:
        error:
          type: string
          description: Human-readable description of the failure.
        code:
          type: string
          enum:
            - invalid_json
            - invalid_request_body
            - invalid_study_guide
            - wallet_required
            - insufficient_credits
            - bad_request
            - missing_api_key
            - invalid_api_key
            - unauthorized
            - launch_permission_denied
            - wallet_access_denied
            - forbidden
            - study_not_found
            - response_not_found
            - not_found
            - study_busy
            - concurrent_modification
            - conflict
            - internal_error
          description: >-
            Stable machine-readable error code. Branch on this, not on the
            `error` text, which may change.
        issues:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: >-
            Present when code is `invalid_request_body`: the schema violations
            (Zod issues), each with a `path` and `message`.
      required:
        - error
        - code
      additionalProperties: false
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable description of the failure.
        code:
          type: string
          enum:
            - invalid_json
            - invalid_request_body
            - invalid_study_guide
            - wallet_required
            - insufficient_credits
            - bad_request
            - missing_api_key
            - invalid_api_key
            - unauthorized
            - launch_permission_denied
            - wallet_access_denied
            - forbidden
            - study_not_found
            - response_not_found
            - not_found
            - study_busy
            - concurrent_modification
            - conflict
            - internal_error
          description: >-
            Stable machine-readable error code. Branch on this, not on the
            `error` text, which may change.
      required:
        - error
        - code
      additionalProperties: false
    Config:
      type: object
      properties:
        interviewMode:
          type: string
          enum:
            - text
            - audio
            - audio_text
            - audio_screen
            - video
            - video_screen
        questionLanguage:
          type: string
          enum:
            - en
            - en-medical
            - fr
            - de
            - de-CH
            - it
            - pt
            - es
            - zh
            - zh-TW
            - zh-HK
            - af
            - sq
            - am
            - ar
            - hy
            - as
            - ast
            - az
            - ba
            - eu
            - be
            - bn
            - bs
            - br
            - bg
            - my
            - ca
            - ceb
            - ny
            - hr
            - cs
            - da
            - nl
            - et
            - fo
            - fi
            - nl-BE
            - ff
            - gl
            - lg
            - ka
            - el
            - gu
            - ht
            - ha
            - haw
            - he
            - hi
            - hu
            - is
            - ig
            - id
            - ga
            - ja
            - jw
            - kea
            - kn
            - kk
            - km
            - ko
            - ku
            - ky
            - lo
            - la
            - lv
            - ln
            - lt
            - luo
            - lb
            - mk
            - mg
            - ms
            - ml
            - mt
            - mi
            - mr
            - mn
            - ne
            - nso
            - 'no'
            - nn
            - oc
            - or
            - pa
            - ps
            - fa
            - pl
            - ro
            - ru
            - sa
            - sr
            - sn
            - sd
            - si
            - sk
            - sl
            - so
            - su
            - sw
            - sv
            - tl
            - tg
            - ta
            - tt
            - te
            - th
            - bo
            - tr
            - tk
            - uk
            - umb
            - ur
            - uz
            - vi
            - cy
            - wo
            - xh
            - yi
            - yo
            - zu
          description: Language code the questions are written in (e.g. en, de).
        availableLanguages:
          type: array
          items: a41d4347-4589-45c7-8f88-31ac3ffc5ab2
          nullable: true
          description: Translation target codes. null/omitted = English only.
        targetPlatforms:
          type: array
          items:
            type: string
            enum:
              - ios
              - android
              - desktop
      additionalProperties: false
    WelcomeMessage:
      type: object
      properties:
        title:
          type: string
        message:
          type: string
      additionalProperties: false
    Block:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this block. Auto-generated when omitted.
            Unique within the payload.
        type:
          type: string
          enum:
            - flat
            - concept
            - screening
        title:
          type: string
        conceptSamplingConfig:
          allOf:
            - $ref: '#/components/schemas/ConceptSamplingConfig'
          nullable: true
        items:
          type: array
          items:
            $ref: '#/components/schemas/Item'
          minItems: 1
      required:
        - type
        - title
        - items
      additionalProperties: false
    ConceptSamplingConfig:
      type: object
      properties:
        concepts:
          type: array
          items:
            $ref: '#/components/schemas/Concept'
          minItems: 1
        subsampleCount:
          type: integer
          exclusiveMinimum: true
          minimum: 0
          nullable: true
          description: How many concepts each participant sees; null = all.
      required:
        - concepts
      additionalProperties: false
    Item:
      oneOf:
        - $ref: '#/components/schemas/OpenEndedItem'
        - $ref: '#/components/schemas/MultipleChoiceItem'
        - $ref: '#/components/schemas/RankingItem'
        - $ref: '#/components/schemas/MatrixItem'
        - $ref: '#/components/schemas/MaxDiffItem'
        - $ref: '#/components/schemas/StatementItem'
      discriminator:
        propertyName: type
        mapping:
          open_ended:
            $ref: '#/components/schemas/OpenEndedItem'
          multiple_choice:
            $ref: '#/components/schemas/MultipleChoiceItem'
          ranking:
            $ref: '#/components/schemas/RankingItem'
          matrix:
            $ref: '#/components/schemas/MatrixItem'
          max_diff:
            $ref: '#/components/schemas/MaxDiffItem'
          statement:
            $ref: '#/components/schemas/StatementItem'
    Concept:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this concept. Auto-generated when omitted.
            Unique within the payload.
        nickname:
          type: string
          minLength: 1
        content:
          type: object
          properties:
            title:
              type: string
            description:
              type: string
              nullable: true
            media:
              type: array
              items:
                $ref: '#/components/schemas/ConceptMedia'
            embed:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required:
                - url
              additionalProperties: false
              nullable: true
          required:
            - title
          additionalProperties: false
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
          description: >-
            Shows this concept only to participants matching the criteria, e.g.
            gate each concept on a screener answer. selectedTemplateOptions
            criteria must reference an item in a block before the concept block.
      required:
        - nickname
        - content
      additionalProperties: false
    OpenEndedItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - open_ended
        followUp:
          type: string
          enum:
            - none
            - light
            - medium
            - heavy
          nullable: true
        addInstructions:
          type: string
          nullable: true
        preferredInput:
          type: string
          enum:
            - text
            - voice
            - screenRecording
            - none
          nullable: true
        screenObservationEnabled:
          type: boolean
          nullable: true
          description: Only applies when preferredInput is screenRecording.
      required:
        - text
        - type
      additionalProperties: false
    MultipleChoiceItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - multiple_choice
        options:
          type: array
          items:
            $ref: '#/components/schemas/Option'
          minItems: 1
          description: >-
            Required unless carryForwardFrom is set; carry-forward questions
            inherit the source's selected options.
        multiSelect:
          type: boolean
          nullable: true
        allowCustomOption:
          type: boolean
          nullable: true
        minSelect:
          type: integer
          exclusiveMinimum: true
          minimum: 0
          nullable: true
        maxSelect:
          type: integer
          exclusiveMinimum: true
          minimum: 0
          nullable: true
        randomizeOptionOrder:
          type: boolean
          nullable: true
        pinnedFinalOption:
          type: boolean
          nullable: true
        carryForwardFrom:
          type: string
          nullable: true
          description: >-
            externalId of an earlier multi-select multiple_choice item; this
            question shows only the options the participant selected there.
      required:
        - text
        - type
      additionalProperties: false
      description: >-
        minSelect/maxSelect must both be set or both null, only when multiSelect
        is true, and minSelect must be <= maxSelect. exclusiveOption is only
        valid on the final option of a multi-select.
    RankingItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - ranking
        options:
          type: array
          items:
            $ref: '#/components/schemas/Option'
          minItems: 1
          description: >-
            Required unless carryForwardFrom is set; carry-forward questions
            rank the source's selected options.
        randomizeOptionOrder:
          type: boolean
          nullable: true
        carryForwardFrom:
          type: string
          nullable: true
          description: >-
            externalId of an earlier multi-select multiple_choice item; this
            question ranks only the options the participant selected there.
      required:
        - text
        - type
      additionalProperties: false
    MatrixItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - matrix
        options:
          type: array
          items:
            $ref: '#/components/schemas/Option'
          minItems: 1
          description: The columns each row is single-select across.
        rows:
          type: array
          items:
            type: object
            properties:
              text:
                type: string
                minLength: 1
            required:
              - text
            additionalProperties: false
          minItems: 1
      required:
        - text
        - type
        - options
        - rows
      additionalProperties: false
    MaxDiffItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - max_diff
        options:
          type: array
          items:
            $ref: '#/components/schemas/Option'
          minItems: 2
          description: The items being compared.
        metric:
          type: string
          nullable: true
        itemsPerScreen:
          anyOf:
            - type: number
              enum:
                - 3
            - type: number
              enum:
                - 4
            - type: number
              enum:
                - 5
          nullable: true
      required:
        - text
        - type
        - options
      additionalProperties: false
    StatementItem:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Stable identifier for this item. Auto-generated when omitted; set it
            only when a conditional (questionId) or carryForwardFrom references
            it. Unique within the payload.
        text:
          type: string
          minLength: 1
        conditional:
          allOf:
            - $ref: '#/components/schemas/Conditional'
          nullable: true
        media:
          type: array
          items:
            $ref: '#/components/schemas/Media'
          nullable: true
        embed:
          allOf:
            - $ref: '#/components/schemas/Embed'
          nullable: true
        type:
          type: string
          enum:
            - statement
        continueButtonText:
          type: string
      required:
        - text
        - type
      additionalProperties: false
    ConceptMedia:
      type: object
      properties:
        name: 91392689-8e1f-43d4-b9b5-328df98f7a81
        url: c4f1ef28-be7f-48a3-9ee1-4ed62fa1d986
        type: 30fd1ea9-7ef7-433c-b221-6e89203d802b
        widthPercentage: 9cf7d3b3-741e-48f0-ab7f-72d12dfe5a39
      required:
        - name
        - url
        - type
      additionalProperties: false
    Conditional:
      type: object
      properties:
        operator:
          type: string
          enum:
            - and
            - or
        criteria:
          type: array
          items:
            $ref: '#/components/schemas/Criterion'
          minItems: 1
      required:
        - operator
        - criteria
      additionalProperties: false
    Media:
      type: object
      properties:
        name:
          type: string
          minLength: 1
        url:
          type: string
          format: uri
        type:
          type: string
          enum:
            - image
            - video
        widthPercentage:
          type: number
        forceWatching:
          type: boolean
      required:
        - name
        - url
        - type
      additionalProperties: false
    Embed:
      type: object
      properties:
        url:
          type: string
          format: uri
        proxyUrl:
          type: string
          format: uri
      required:
        - url
      additionalProperties: false
    Option:
      type: object
      properties:
        externalId:
          type: string
          minLength: 1
          description: >-
            Optional handle so a conditional can reference this option by id.
            Unique within the payload.
        text:
          type: string
          minLength: 1
        status:
          type: string
          enum:
            - approve
            - reject
            - neutral
          nullable: true
          default: null
          description: Required inside screening blocks, null elsewhere.
        exclusiveOption:
          type: boolean
          description: >-
            Only valid on the final option of a multi-select multiple_choice
            question; selecting it clears and locks the other options.
      required:
        - text
      additionalProperties: false
    Criterion:
      oneOf:
        - $ref: '#/components/schemas/SelectedTemplateOptionsCriterion'
        - $ref: '#/components/schemas/SearchParamCriterion'
      discriminator:
        propertyName: type
        mapping:
          selectedTemplateOptions:
            $ref: '#/components/schemas/SelectedTemplateOptionsCriterion'
          searchParam:
            $ref: '#/components/schemas/SearchParamCriterion'
    SelectedTemplateOptionsCriterion:
      type: object
      properties:
        type:
          type: string
          enum:
            - selectedTemplateOptions
        questionId:
          type: string
          minLength: 1
          description: externalId of an earlier multiple_choice or matrix item.
        matchingCriteria:
          type: string
          enum:
            - mustSelect
            - mustNotSelect
        choices:
          type: array
          items:
            type: string
          minItems: 1
          description: >-
            Option externalIds (falls back to option text). Columns for a matrix
            source.
        matrixRow:
          type: string
          nullable: true
          description: Required only for a matrix source; the exact row text.
      required:
        - type
        - questionId
        - matchingCriteria
        - choices
      additionalProperties: false
    SearchParamCriterion:
      type: object
      properties:
        type:
          type: string
          enum:
            - searchParam
        parameter:
          type: string
          minLength: 1
        value:
          type: string
      required:
        - type
        - parameter
        - value
      additionalProperties: false
  responses:
    Unauthorized:
      description: 'Missing or invalid API key. Codes: `missing_api_key`, `invalid_api_key`.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            missingApiKey:
              value:
                error: Missing x-api-key header
                code: missing_api_key
            invalidApiKey:
              value:
                error: Invalid API key
                code: invalid_api_key
    Forbidden:
      description: 'Key''s user not permitted for this resource. Codes: `forbidden`.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            forbidden:
              value:
                error: API key user is not a member of the key's organization
                code: forbidden
    ServerError:
      description: >-
        Internal error (details are logged server-side, not returned). Codes:
        `internal_error`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            internalError:
              value:
                error: Internal server error
                code: internal_error
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````