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

# Créer une session

> Crée une session attachée à la version publiée active. La première question est obtenue ensuite avec POST /v1/sessions/{session_id}/next. initial_history permet de reprendre une conversation déjà commencée.



## OpenAPI

````yaml /openapi.fr.yaml post /v1/sessions
openapi: 3.1.0
info:
  title: Zelinqa — API V1
  version: 1.0.0
  summary: >-
    Contrat public du runtime Zelinqa et de la configuration des bases de
    questions.
  description: >-
    Contrat public de l'API Zelinqa V1 sur https://api.zelinqa.ai. La clé API
    identifie le domaine et ses droits. Les mutations utilisent Idempotency-Key
    ; celles d'une session existante utilisent aussi state_version. Les sessions
    restent attachées à leur version publiée.
  contact:
    name: Zelinqa
    url: https://docs.zelinqa.ai
  license:
    name: Proprietary — Zelinqa SAS
    identifier: LicenseRef-Zelinqa-Proprietary
servers:
  - url: https://api.zelinqa.ai
    description: API publique Zelinqa
security:
  - ApiKeyAuth: []
tags:
  - name: sessions
    description: >
      Cycle de vie d'une conversation Zelinqa : création, sélection de la
      question

      suivante, mises à jour hors tour, reprise et retour de résultat.
  - name: configuration
    description: |
      Lecture et modification de la configuration éditoriale d'un domaine, puis
      publication asynchrone de l'artefact moteur.
paths:
  /v1/sessions:
    post:
      tags:
        - sessions
      summary: Créer une session
      description: >-
        Crée une session attachée à la version publiée active. La première
        question est obtenue ensuite avec POST /v1/sessions/{session_id}/next.
        initial_history permet de reprendre une conversation déjà commencée.
      operationId: createSession
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SessionCreateRequest'
            examples:
              minimal:
                summary: Création nominale
                value: {}
              avec_reference_client:
                summary: Corrélation avec un identifiant de l'intégrateur
                value:
                  client_reference: crm-lead-8842
                  max_turns: 15
              reprise_conversation:
                summary: Conversation déjà commencée hors Zelinqa
                value:
                  client_reference: crm-lead-8843
                  initial_history:
                    - role: assistant
                      message_id: msg_1
                      text: Bonjour, que recherchez-vous ?
                    - role: user
                      message_id: msg_2
                      text: Un canapé pour mon salon, plutôt contemporain.
      responses:
        '201':
          description: Session créée.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionStateResponse'
              examples:
                session_neuve:
                  $ref: '#/components/examples/SessionNeuve'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/InsufficientScope'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
        '410':
          $ref: '#/components/responses/CompiledArtifactUnavailable'
        '422':
          $ref: '#/components/responses/InvalidChoice'
        '503':
          $ref: '#/components/responses/IdempotencyContention'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema:
        type: string
        minLength: 8
        maxLength: 128
      description: >
        Clé unique par mutation logique, choisie par l'appelant.


        Même clé et même corps renvoient exactement la réponse d'origine, sans

        rejouer l'effet : aucun retry ne double `turn_count`, un outcome, un

        événement, un feedback ou une publication. Même clé avec un corps
        différent

        produit `409 idempotency_key_reused`.


        Les enregistrements sont isolés par tenant et par opération, et sont
        purgés

        après **24 heures**. Passé ce délai, la même clé est traitée comme
        neuve.
  schemas:
    SessionCreateRequest:
      type: object
      additionalProperties: false
      description: |
        Le client ne choisit ni la version de configuration, ni une politique
        d'accusé de réception : la session épingle en interne la version publiée
        active au moment de sa création.
      properties:
        client_reference:
          type: string
          minLength: 1
          maxLength: 128
          description: >-
            Référence opaque de l'intégrateur, renvoyée telle quelle pour
            corrélation.
        max_turns:
          type: integer
          minimum: 1
          maximum: 100
          description: >
            Surcharge la limite souple définie dans la configuration. Atteindre
            cette

            limite ne coupe pas la conversation : `/next` continue de proposer
            la

            meilleure question avec un avertissement.
        initial_history:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/InitialHistoryItem'
          description: >
            Historique de reprise, consommé une seule fois en mémoire pour
            construire

            l'état initial. Jamais persisté, jamais renvoyé.
    SessionStateResponse:
      type: object
      additionalProperties: false
      required:
        - request_id
        - session_id
        - client_reference
        - status
        - turn_count
        - max_turns
        - turns_remaining
        - question_state
        - targets
        - progress
        - pending_decision
        - degraded
        - versions
      properties:
        request_id:
          type: string
        session_id:
          type: string
        client_reference:
          type:
            - string
            - 'null'
        status:
          type: string
          enum:
            - active
            - completed
            - stopped
        turn_count:
          type: integer
          minimum: 0
        max_turns:
          type: integer
          minimum: 1
        turns_remaining:
          type: integer
          minimum: 0
        question_state:
          $ref: '#/components/schemas/PublicQuestionState'
        targets:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/PublicTargetState'
          description: >
            État sparse : seules les cibles réellement touchées sont présentes.
            Une

            cible absente est inconnue et sans couverture.
        progress:
          $ref: '#/components/schemas/ProgressView'
        pending_decision:
          oneOf:
            - $ref: '#/components/schemas/PendingDecisionView'
            - type: 'null'
        degraded:
          type: boolean
        versions:
          $ref: '#/components/schemas/VersionInfo'
    InitialHistoryItem:
      type: object
      additionalProperties: false
      required:
        - role
      properties:
        role:
          type: string
          enum:
            - user
            - assistant
        message_id:
          type: string
          minLength: 1
          maxLength: 128
          description: Référence conservée même lorsque le verbatim n'est pas persisté.
        question_id:
          type: string
          minLength: 1
          maxLength: 128
          description: >-
            Renseigné seulement si ce message correspond à une question connue
            du corpus.
        text:
          type: string
          minLength: 1
          maxLength: 8000
        structured_answer:
          $ref: '#/components/schemas/StructuredAnswer'
        occurred_at:
          type: string
          format: date-time
      anyOf:
        - required:
            - text
        - required:
            - structured_answer
    PublicQuestionState:
      type: object
      additionalProperties: false
      required:
        - outcomes
      description: >
        Aucun index `asked_ids`, `answered_ids` ou `refused_ids` n'est persisté
        ni

        exposé : ces ensembles se reconstruisent depuis `outcomes`.
      properties:
        outcomes:
          type: array
          items:
            $ref: '#/components/schemas/QuestionOutcomeRecord'
    PublicTargetState:
      type: object
      additionalProperties: false
      required:
        - kind
        - coverage
      description: >
        Vue publique d'une cible. Les preuves sémantiques détaillées, les deltas
        de

        couverture et les références d'embedding restent internes au

        moteur et ne sont jamais renvoyés.
      properties:
        kind:
          type: string
          enum:
            - data
            - exploration
          description: >
            `data` désigne une information de réussite : une donnée concrète
            dont la

            collecte permet de déclarer l'objectif atteint.


            `exploration` est la cible interne d'une question qui n'est reliée à

            aucune information de réussite. Elle mesure ce que la conversation a
            déjà

            couvert et évite les répétitions, mais ne bloque jamais la réussite
            de

            l'objectif. Les nouvelles publications sans prototypes évaluent
            directement

            les réponses réelles. Les sessions épinglées à un ancien artefact

            conservent leur méthode de couverture historique.
        status:
          type: string
          enum:
            - tentative
            - confirmed
            - conflicted
            - not_applicable
          description: >
            Présent uniquement pour `kind: data`. Une cible inconnue est absente
            de

            l'état plutôt que portée avec un statut `unknown`.


            `tentative` porte une valeur probable : elle fait monter `coverage`

            mais ne permet jamais de conclure ;

            `conflicted` signale plusieurs valeurs valides contradictoires ;

            `not_applicable` satisfait l'information sans valeur.
        value:
          description: >-
            Présente uniquement pour une information de réussite possédant une
            valeur courante.
        coverage:
          type: number
          minimum: 0
          maximum: 1
          description: >
            Ce que la conversation a déjà obtenu sur cette cible.


            Pour une information de réussite : `1` quand elle est `confirmed` ou

            `not_applicable`, `0` quand rien n'a été recueilli, et une valeur

            **intermédiaire** quand le statut est `tentative` — une valeur

            probable a été captée mais n'est pas encore assez fiable pour

            conclure. Une donnée `conflicted` retombe à `0` : des valeurs

            contradictoires n'apportent aucune certitude.


            Pour une cible d'exploration sans prototypes : meilleur soutien
            actif

            à la cible, dérivé des réponses réelles ; une réponse suffisante
            vaut

            `1`, sans devoir couvrir plusieurs exemples alternatifs. Une
            correction

            explicite peut réduire cette couverture. Pour les anciennes
            publications,

            le calcul historique sur les prototypes reste inchangé.


            ⚠️ `coverage` sert à mesurer l'avancement et à classer les
            questions,

            **jamais à décider de la réussite**. La complétion d'un

            dimension se calcule à partir de `status`, où seuls `confirmed`

            et `not_applicable` comptent : une information `tentative` fait

            monter la progression visible sans jamais permettre de déclarer

            l'objectif atteint. Les deux grandeurs se ressemblent et ne se

            substituent pas l'une à l'autre.
    ProgressView:
      type: object
      additionalProperties: false
      required:
        - objective
        - dimensions
      properties:
        objective:
          $ref: '#/components/schemas/ObjectiveProgress'
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/DimensionProgress'
    PendingDecisionView:
      type: object
      additionalProperties: false
      required:
        - decision_id
        - candidates
      description: >
        Décision proposée et pas encore résolue. Les candidats sont réhydratés
        depuis

        la configuration épinglée : après un crash, relire la session suffit
        pour

        reprendre exactement où l'on s'était arrêté. Aucun jeton de reprise
        n'existe.
      properties:
        decision_id:
          type: string
        candidates:
          type: array
          minItems: 1
          maxItems: 10
          items:
            $ref: '#/components/schemas/Candidate'
    VersionInfo:
      type: object
      additionalProperties: false
      required:
        - state_version
        - engine_version
        - api_version
      description: >
        La version de configuration épinglée par la session n'est pas exposée :
        le

        client ne la choisit pas et ne doit pas s'y adosser.
      properties:
        state_version:
          type: integer
          minimum: 0
          description: À renvoyer dans la mutation suivante de cette session.
        engine_version:
          type: string
        api_version:
          type: string
          const: '1.0'
    ErrorEnvelope:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - request_id
        - details
      description: Enveloppe uniforme de toutes les erreurs métier.
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
          minLength: 1
        request_id:
          type: string
          minLength: 1
        details:
          type: object
          additionalProperties: true
    StructuredAnswer:
      type: object
      additionalProperties: false
      required:
        - choice_ids
      description: >
        Réponse à une question à choix. Le mapping choix vers information de
        réussite

        est déterministe et compilé à la publication : aucun appel LLM n'est
        effectué

        pour l'interpréter.
      properties:
        choice_ids:
          type: array
          minItems: 1
          maxItems: 50
          uniqueItems: true
          items:
            type: string
            minLength: 1
            maxLength: 128
        free_text:
          type: string
          minLength: 1
          maxLength: 4000
          description: Complément libre, autorisé uniquement pour une question `semi_open`.
    QuestionOutcomeRecord:
      type: object
      additionalProperties: false
      required:
        - question_id
        - decision_id
        - outcome
        - source
      properties:
        question_id:
          type: string
        decision_id:
          type:
            - string
            - 'null'
          description: Nul lorsque la question a été traitée hors d'une décision Zelinqa.
        outcome:
          $ref: '#/components/schemas/QuestionOutcome'
        source:
          type: string
          enum:
            - client
            - inferred
          description: >-
            Indique si l'outcome a été fourni par le client ou résolu par
            Zelinqa.
        message_id:
          type:
            - string
            - 'null'
        occurred_at:
          type:
            - string
            - 'null'
          format: date-time
    ObjectiveProgress:
      type: object
      additionalProperties: false
      required:
        - computed_status
        - progress
        - client_override
        - effective_status
      properties:
        computed_status:
          $ref: '#/components/schemas/ProgressStatus'
        progress:
          type: number
          minimum: 0
          maximum: 1
          description: |
            Agrégation des dimensions pondérée par leur rôle de complétion. Les
            dimensions exclus sortent du dénominateur.
        client_override:
          oneOf:
            - $ref: '#/components/schemas/ObjectiveClientOverrideView'
            - type: 'null'
        effective_status:
          $ref: '#/components/schemas/ProgressStatus'
    DimensionProgress:
      type: object
      additionalProperties: false
      required:
        - id
        - order_position
        - completion_role
        - computed_status
        - progress
        - client_override
        - effective_status
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 128
        order_position:
          type: integer
          minimum: 0
        completion_role:
          $ref: '#/components/schemas/CompletionRole'
        computed_status:
          $ref: '#/components/schemas/ProgressStatus'
        progress:
          type: number
          minimum: 0
          maximum: 1
        client_override:
          oneOf:
            - $ref: '#/components/schemas/DimensionClientOverrideView'
            - type: 'null'
        effective_status:
          type: string
          enum:
            - not_started
            - in_progress
            - covered
            - blocked
            - excluded
          description: >
            Statut consommable par le client après application de
            `client_override`

            au `computed_status` : sans override, le statut calculé ; `achieved`

            force `covered` ; `not_achieved` conserve le statut calculé sauf que

            `covered` redevient `in_progress` ; `excluded` retire la dimension
            de

            la sélection et des agrégations de l'objectif.
    Candidate:
      type: object
      additionalProperties: false
      required:
        - rank
        - question_id
        - text
        - type
        - choices
        - target_ids
      description: |
        **Invariant garanti par le moteur**, couvert par les tests de contrat :
        `type: open` implique `choices` vide ; tout autre type implique au moins
        deux choix.
      properties:
        rank:
          type: integer
          minimum: 1
          maximum: 10
        question_id:
          type: string
          minLength: 1
          maxLength: 128
          description: >-
            Toujours un identifiant valide du corpus publié, y compris pour un
            repli.
        text:
          type: string
          minLength: 1
          maxLength: 4000
          description: >
            Libellé publié de la question. L'agent hôte reste libre de le
            reformuler :

            Zelinqa sait rattacher un texte reformulé à sa question au tour
            suivant.
        type:
          $ref: '#/components/schemas/QuestionType'
        choices:
          type: array
          maxItems: 50
          items:
            $ref: '#/components/schemas/CandidateChoice'
          description: Vide pour une question ouverte.
        target_ids:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            minLength: 1
            maxLength: 128
          description: Cibles que cette question adresse, principale en premier.
        selection_mode:
          $ref: '#/components/schemas/QuestionSelectionMode'
          description: |
            Présent pour `semi_open` afin d'indiquer si l'appelant accepte un ou
            plusieurs `choice_ids`. Absent pour les autres types.
    ErrorCode:
      type: string
      description: Catalogue fermé des erreurs métier V1.
      enum:
        - unauthorized
        - insufficient_scope
        - idempotency_contention
        - state_version_conflict
        - idempotency_key_reused
        - unknown_session
        - invalid_previous_turn
        - constraint_no_match
        - invalid_choice
        - compiled_artifact_unavailable
        - configuration_validation_failed
        - compilation_in_progress
        - unknown_configuration
        - unknown_compilation
    QuestionOutcome:
      type: string
      enum:
        - asked_answered
        - asked_no_answer
        - refused
      description: >
        Résultat d'une question effectivement posée.


        - `asked_answered` : question posée et réponse exploitable reçue ;

        - `asked_no_answer` : question posée, aucune réponse exploitable ;

        - `refused` : refus explicite de répondre.


        Une question jamais posée n'a pas de résultat : elle est simplement
        absente.

        Il n'existe pas de valeur `skipped` — une proposition que l'agent n'a
        pas

        utilisée est journalisée comme décision ignorée, jamais comme un faux

        résultat sur la question.
    ProgressStatus:
      type: string
      enum:
        - not_started
        - in_progress
        - covered
        - blocked
    ObjectiveClientOverrideView:
      type: object
      additionalProperties: false
      required:
        - status
      properties:
        status:
          $ref: '#/components/schemas/ObjectiveOverrideValue'
        updated_at:
          type: string
          format: date-time
    CompletionRole:
      type: string
      enum:
        - blocking
        - contributing
        - optional
      description: >-
        Rôle dans la qualification globale : les données des dimensions blocking
        doivent être conclues ; une dimension blocking sans donnée ne bloque pas
        seule la réussite. Les dimensions contributing participent au seuil
        moyen du niveau. Les dimensions optional n'imposent pas de seuil de
        couverture, mais les informations de réussite configurées restent
        exigées, sauf exclusion ou décision explicite du client.
    DimensionClientOverrideView:
      type: object
      additionalProperties: false
      required:
        - status
      properties:
        status:
          $ref: '#/components/schemas/DimensionOverrideValue'
        updated_at:
          type: string
          format: date-time
    QuestionType:
      type: string
      enum:
        - open
        - single_choice
        - multiple_choice
        - semi_open
      description: |
        - `open` : réponse libre, aucun choix ;
        - `single_choice` : un seul choix parmi la liste ;
        - `multiple_choice` : plusieurs choix possibles ;
        - `semi_open` : choix proposés, complément libre autorisé via
          `structured_answer.free_text`.

        Pour `semi_open`, `selection_mode` précise si un ou plusieurs choix sont
        permis en plus du complément libre.
    CandidateChoice:
      type: object
      additionalProperties: false
      required:
        - choice_id
        - label
      properties:
        choice_id:
          type: string
          minLength: 1
          maxLength: 128
        label:
          type: string
          minLength: 1
          maxLength: 500
    QuestionSelectionMode:
      type: string
      enum:
        - single
        - multiple
    ObjectiveOverrideValue:
      type: string
      enum:
        - achieved
        - not_achieved
    DimensionOverrideValue:
      type: string
      enum:
        - achieved
        - not_achieved
        - excluded
      description: >
        `achieved` force la dimension à couvert. `not_achieved` empêche une

        complétion calculée prématurée. `excluded` le retire de la sélection et
        des

        dénominateurs de progression de l'objectif.
  examples:
    SessionNeuve:
      summary: Session tout juste créée, aucun tour joué
      value:
        request_id: req_1001
        session_id: ses_01J8Z
        client_reference: crm-lead-8842
        status: active
        turn_count: 0
        max_turns: 15
        turns_remaining: 15
        question_state:
          outcomes: []
        targets: {}
        progress:
          objective:
            computed_status: not_started
            progress: 0
            client_override: null
            effective_status: not_started
          dimensions:
            - id: so_besoin
              order_position: 0
              completion_role: blocking
              computed_status: not_started
              progress: 0
              client_override: null
              effective_status: not_started
            - id: so_budget
              order_position: 1
              completion_role: blocking
              computed_status: not_started
              progress: 0
              client_override: null
              effective_status: not_started
            - id: so_livraison
              order_position: 2
              completion_role: contributing
              computed_status: not_started
              progress: 0
              client_override: null
              effective_status: not_started
        pending_decision: null
        degraded: false
        versions:
          state_version: 0
          engine_version: 1.0.0
          api_version: '1.0'
  responses:
    Unauthorized:
      description: >-
        Réponse 401 possible au niveau de l'application. Une clé absente ou
        invalide est généralement refusée en 403 par la passerelle, sans
        enveloppe métier garantie.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: unauthorized
            message: Clé d'intégration absente ou invalide.
            request_id: req_9000
            details: {}
    InsufficientScope:
      description: >-
        Accès refusé. La passerelle peut renvoyer 403 pour une clé absente,
        invalide, expirée, révoquée ou dépourvue du scope requis, sans enveloppe
        métier garantie.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: insufficient_scope
            message: Cette clé ne permet pas de publier une configuration.
            request_id: req_9001
            details:
              required_scopes:
                - configuration:publish
              granted_scopes:
                - configuration:read
                - configuration:write
    IdempotencyConflict:
      description: La clé d'idempotence a déjà servi pour un corps différent.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: idempotency_key_reused
            message: Cette clé d'idempotence est déjà associée à une autre requête.
            request_id: req_9002
            details:
              idempotency_key: create-session-8842
    CompiledArtifactUnavailable:
      description: >
        L'artefact compilé épinglé par la session est réellement inaccessible.
        Une

        configuration simplement remplacée par une version plus récente ne
        produit pas

        cette erreur : l'ancienne version reste lisible pour terminer les
        sessions qui

        l'utilisent déjà.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: compiled_artifact_unavailable
            message: >-
              L'artefact moteur de cette session est temporairement
              indisponible.
            request_id: req_9010
            details:
              session_id: ses_01J8Z
    InvalidChoice:
      description: Une valeur fournie n'appartient pas au schéma ou aux choix publiés.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: invalid_choice
            message: >-
              La valeur fournie n'est pas valide pour cette information de
              réussite.
            request_id: req_9014
            details:
              data_id: delivery_window
              invalid_value: dans_deux_ans
    IdempotencyContention:
      description: >
        La clé d'idempotence n'a pas pu être réservée après deux tentatives, à
        cause

        d'un cycle anormal de requêtes concurrentes portant la même clé.


        Ce n'est **pas** une erreur du client et ce n'est pas un conflit :
        réessayer

        après un court délai a des chances d'aboutir. À distinguer de

        `idempotency_key_reused`, qui est définitif pour ce couple clé/corps.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            code: idempotency_contention
            message: La clé d'idempotence n'a pas pu être réservée, réessayez.
            request_id: req_9017
            details:
              idempotency_key: next-ses01J8Z-turn-4
              retry_after_seconds: 1
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: Zelinqa API key
      description: >-
        Envoyez la clé API dans Authorization: Bearer <clé>. Elle identifie le
        domaine et les droits autorisés. Ne transmettez pas d'en-têtes
        d'identité internes.

````

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