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

# Get a Composer Session

> The session's current preview and its conversation, newest first. Use it to pick a session back up, or to show someone how the agent was designed.

The agent a session is currently holding, plus the conversation that shaped it.

Use it to pick up a session your integration started earlier — after a page reload, in another process, or when a human comes back to a preview a day later — and to render the thread of how the agent was designed.

```javascript theme={null}
{
  "sessionId": "9f8c1d2e-4b7a-4c3d-9e1f-2a5b6c7d8e90",
  "agent": { "name": "Senior Backend Phone Screen", "type": "PHONE", "flow": { "…": "…" } },
  "messages": [
    {
      "id": "…",
      "role": "assistant",
      "content": "Your agent now asks about relocation, and the whole call is in Slovak.",
      "changes": ["Added a relocation question", "Set the language to SK"],
      "createdAt": "2026-08-18T10:22:00.000Z"
    },
    { "id": "…", "role": "user", "content": "Also ask about relocation, and make the whole call Slovak.", "createdAt": "2026-08-18T10:22:00.000Z" }
  ],
  "expiresAt": "2026-09-17T10:15:00.000Z"
}
```

`agent` is the current preview — the same body [`POST /agents`](/api-reference/agents/create-agent) accepts verbatim, reflecting every refinement so far.

## Paging the conversation

`messages` is newest first. When there is an older page, `nextCursor` is present; pass it back as `cursor` to continue.

```javascript theme={null}
GET /agents/composer/{sessionId}?cursor=MjAyNi0wOC0xOFQxMDoyMjowMC4wMDBafG1zZy0x
```

No `nextCursor` means you have reached the beginning of the conversation.

<Info>
  The cursor is opaque. Do not construct or parse one — pass back what you were given. An
  unreadable cursor is treated as no cursor, so you get the newest page rather than an error.
</Info>

## Scope and lifetime

Requires the `agents` read scope. An unknown session, an expired one, and one belonging to another company are all a `404`.

Sessions live 30 days; `expiresAt` says when this one goes. Once you create the agent, the conversation moves with it and is no longer read here — it is part of the agent.


## OpenAPI

````yaml GET /agents/composer/{sessionId}
openapi: 3.0.0
info:
  title: InstaView API
  description: |-
    InstaView API Documentation

    ## Authentication

    All endpoints require API key authentication using Bearer token:
    ```
    Authorization: Bearer sk_your_api_key_here
    ```

    ## API Key Management

    The API Key module provides comprehensive key management for:
    - **Direct Client Keys**: Company-scoped keys for your applications
    - **ATS Partner Keys**: Resource-scoped keys for ATS integrations

    ### Key Features
    - HMAC-SHA256 hashing for API key storage
    - Configurable rate limiting
    - Comprehensive audit logging
    - Company-level isolation
    - Resource scoping for ATS partners
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.instaview.sk
    description: Production API Gateway
security: []
tags: []
paths:
  /agents/composer/{sessionId}:
    get:
      tags:
        - Agents
      summary: Get a composer session
      description: >-
        The session's current preview and its conversation, newest first. Use it
        to pick a session back up, or to show someone how the agent was
        designed.
      operationId: PublicAgentComposerController_getSession_v1
      parameters:
        - name: sessionId
          required: true
          in: path
          description: The composer session id returned by `POST /agents/composer`.
          schema:
            type: string
            format: uuid
        - name: cursor
          required: false
          in: query
          description: Opaque cursor from a previous page's `nextCursor`.
          schema:
            type: string
        - name: companyId
          required: false
          in: query
          description: >-
            Required for ATS API keys to specify which company to access.
            Ignored for standard company API keys.
          schema:
            type: string
      responses:
        '200':
          description: The session, its current preview and a page of the conversation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicComposerSessionDetailDto'
        '404':
          description: No live composer session with that id belongs to your company.
      security:
        - bearer: []
components:
  schemas:
    PublicComposerSessionDetailDto:
      type: object
      properties:
        sessionId:
          type: string
          format: uuid
        agent:
          $ref: '#/components/schemas/PublicComposerAgentPreviewDto'
        messages:
          type: array
          items:
            $ref: '#/components/schemas/PublicComposerTurnDto'
          description: The conversation so far, newest first.
        nextCursor:
          type: string
          description: >-
            Pass as `cursor` to fetch the next (older) page. Absent at the start
            of the conversation.
        expiresAt:
          format: date-time
          type: string
      required:
        - sessionId
        - agent
        - messages
        - expiresAt
    PublicComposerAgentPreviewDto:
      type: object
      description: >-
        The agent the composer would build. There is no `id`: this agent does
        not exist yet. Post this object to `POST /agents` to create it — it is
        accepted verbatim, with no ids or `schemaVersion` to strip first.
      properties:
        name:
          type: string
          example: Senior Developer Phone Screen
        type:
          type: string
          enum:
            - ONLINE
            - PHONE
        language:
          type: string
          enum:
            - EN
            - SK
            - CS
        duration:
          type: number
        voiceId:
          type: string
        backgroundSound:
          type: string
          enum:
            - OFFICE
            - 'OFF'
        companyPhoneNumberId:
          type: string
        metadata:
          type: object
        overrides:
          $ref: '#/components/schemas/AgentOverrides'
        flow:
          $ref: '#/components/schemas/ConversationFlow'
        guardrails:
          $ref: '#/components/schemas/AgentGuardrailsConfig'
        contextConfig:
          $ref: '#/components/schemas/AgentContextConfig'
        analyticsConfig:
          $ref: '#/components/schemas/AgentAnalyticsConfig'
      required:
        - type
        - flow
    PublicComposerTurnDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        role:
          type: string
          enum:
            - user
            - assistant
        content:
          type: string
          description: >-
            For an assistant turn: what the agent does, in plain language, in at
            most ten sentences. For a user turn: what you asked for.
          example: >-
            Your agent opens by introducing itself and confirming it's speaking
            with the right person. It then works through Go and Postgres
            experience…
        changes:
          type: array
          items:
            type: string
          description: Short labels for what this turn changed. Empty on your own messages.
          example:
            - Added a relocation question
            - Set the language to Slovak
        createdAt:
          format: date-time
          type: string
      required:
        - id
        - role
        - content
        - createdAt
    AgentOverrides:
      type: object
      description: >-
        Who the agent presents itself as on a call, when that is not the company
        your API key belongs to. Applies to every agent, template or custom.
        Nothing about ownership changes: billing, analytics and phone-number
        routing keep the real company. You are responsible for having the right
        to speak in the name you send.
      properties:
        companyName:
          type: string
          description: >-
            Company name the agent introduces itself with. Omit to use your own
            company's name.
          minLength: 1
          maxLength: 100
          example: Acme Manufacturing
        companyDescription:
          type: string
          description: >-
            Company description the agent may draw on. Falls back to your own
            company's description independently of `companyName`, so send it
            alongside a name override — otherwise the agent introduces itself as
            one company and describes another.
          minLength: 1
          maxLength: 1000
          example: >-
            Acme makes industrial fasteners and employs 400 people across
            Slovakia.
    ConversationFlow:
      type: object
      description: >-
        The conversation a custom agent runs: an opening message, the sections
        to work through, and a closing message. Sending a flow on an agent makes
        it a custom agent — do not also send `focus`.
      required:
        - firstMessage
        - sections
        - lastMessage
      properties:
        schemaVersion:
          type: string
          readOnly: true
          description: >-
            The flow schema this document is expressed in. Assigned by InstaView
            — sending it is rejected with 400, so an integration written today
            keeps working when the schema moves.
          example: 1.0.0
        firstMessage:
          $ref: '#/components/schemas/FlowFirstMessageBlock'
        sections:
          type: array
          description: >-
            The body of the conversation, worked through in order. At least one
            section is required.
          minItems: 1
          maxItems: 100
          items:
            $ref: '#/components/schemas/FlowBlock'
        lastMessage:
          $ref: '#/components/schemas/FlowLastMessageBlock'
    AgentGuardrailsConfig:
      type: object
      description: Rules the agent must obey during the call. Custom agents only.
      required:
        - rules
      properties:
        rules:
          type: array
          description: >-
            Stated to the agent verbatim as instructions. Replaces the stored
            rules; an empty array removes them all.
          maxItems: 50
          items:
            type: string
            minLength: 1
            maxLength: 500
          example:
            - Never quote a price
            - Never promise a delivery date
    AgentContextConfig:
      type: object
      description: >-
        Who the agent is and what the call is about. Custom agents only. Company
        information is NOT set here — the description on your company profile is
        given to every custom agent automatically and resolved per call.
      properties:
        role:
          type: string
          description: Who the agent should present itself as.
          maxLength: 500
          example: an account executive for Acme
        communicationStyle:
          type: string
          description: >-
            How the agent speaks. The same list the visual builder offers, so an
            agent created over the API stays editable there.
          enum:
            - professional
            - friendly
            - warm and empathetic
            - assertive
            - concise and direct
            - enthusiastic
            - casual
          example: concise and direct
        callToAction:
          type: string
          description: What the call is trying to achieve.
          maxLength: 500
          example: book a 30-minute demo
    AgentAnalyticsConfig:
      type: object
      description: >-
        What the agent extracts, scores, decides and labels after every call.
        Custom agents only — sending it without a `flow` is rejected. The
        results come back on the conversation as `analytics` and on the
        `analysis.completed` webhook.


        Per-question scoring is **not** here: it is set inline on each looping
        question in the `flow` (`importance` / `weight`), because a question is
        addressed by an id InstaView assigns.
      properties:
        extractionTargets:
          type: array
          description: >-
            The values to pull out of every call. A target with an `ideal` also
            counts toward the match score.
          maxItems: 50
          items:
            $ref: '#/components/schemas/AnalyticsExtractionTarget'
        scoringCriteria:
          type: array
          description: >-
            Holistic judgements over the whole call that are not a single field
            or question, e.g. “handled objections”.
          maxItems: 25
          items:
            $ref: '#/components/schemas/AnalyticsScoringCriterion'
        outcomes:
          type: array
          description: >-
            Did the call achieve what it was for? Each outcome is decided met /
            not met per call.
          maxItems: 25
          items:
            $ref: '#/components/schemas/AnalyticsOutcome'
        outputTags:
          type: array
          description: Labels the AI may assign to a call.
          maxItems: 25
          items:
            $ref: '#/components/schemas/AnalyticsOutputTag'
        capture:
          allOf:
            - $ref: '#/components/schemas/AnalyticsCapture'
          description: >-
            Which qualitative artefacts to produce. Every flag defaults to
            `true`, so an omitted `capture` is not “capture nothing”.
    FlowFirstMessageBlock:
      type: object
      description: >-
        What the agent says first. Supports `{{contact.*}}` variables, injected
        per call.
      required:
        - type
        - text
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - first_message
        label:
          type: string
          description: Optional name for this block, shown in the visual builder.
          example: Qualify budget
        text:
          type: string
          description: The opening line.
          example: Hi {{contact.firstName}}, do you have two minutes?
    FlowBlock:
      description: One section of the conversation. `type` selects the shape.
      oneOf:
        - $ref: '#/components/schemas/FlowSequentialBlock'
        - $ref: '#/components/schemas/FlowLoopingBlock'
        - $ref: '#/components/schemas/FlowConditionalBlock'
        - $ref: '#/components/schemas/FlowHumanHandoffBlock'
      discriminator:
        propertyName: type
        mapping:
          sequential:
            $ref: '#/components/schemas/FlowSequentialBlock'
          looping:
            $ref: '#/components/schemas/FlowLoopingBlock'
          conditional:
            $ref: '#/components/schemas/FlowConditionalBlock'
          human_handoff:
            $ref: '#/components/schemas/FlowHumanHandoffBlock'
    FlowLastMessageBlock:
      type: object
      description: What the agent says before hanging up.
      required:
        - type
        - text
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - last_message
        label:
          type: string
          description: Optional name for this block, shown in the visual builder.
          example: Qualify budget
        text:
          type: string
          description: The closing line.
          example: Thanks for your time — have a great day!
    AnalyticsExtractionTarget:
      type: object
      description: One value to pull out of every call.
      required:
        - label
        - type
      properties:
        key:
          type: string
          description: >-
            Stable name this item's results come back under. Optional — omit it
            and InstaView derives a slug of `label` (`Budget confirmed` →
            `budget_confirmed`). Set it when your integration reads the results
            by name: a key you choose survives a later `label` change, a derived
            one does not. If two derived keys collide, the later one gets a
            numeric suffix (`budget`, `budget_2`). Must be unique within its
            list — a duplicate you sent is rejected with `400`, never renamed.
            Reserved names (`__proto__`, `constructor`, `prototype`) are
            rejected. Editing the agent in the visual builder re-derives the key
            from the label.
          maxLength: 64
          pattern: ^[A-Za-z0-9_]{1,64}$
          example: budget_confirmed
        label:
          type: string
          description: >-
            What to extract, in your own words. Also the default source of
            `key`.
          maxLength: 200
          example: Budget confirmed
        type:
          type: string
          description: >-
            The value's type. The extracted value is coerced to it, or returned
            as `null`.
          enum:
            - string
            - number
            - bool
            - enum
          example: bool
        enumValues:
          type: array
          description: The allowed values. Required when `type` is `enum`.
          maxItems: 50
          items:
            type: string
          example:
            - hot
            - warm
            - cold
        ideal:
          type: string
          description: >-
            What a good value looks like. Its PRESENCE is what makes this field
            count toward the match score — a field with no `ideal` is extracted
            but not scored.
          maxLength: 500
          example: A confirmed budget of at least 10k
        importance:
          type: string
          description: >-
            How much a miss matters. `REQUIRED` gates the score; `PREFERRED`
            contributes by weight.
          enum:
            - REQUIRED
            - PREFERRED
          example: PREFERRED
        weight:
          type: number
          description: >-
            Relative contribution to the match score. Weights are relative to
            each other, not a budget that must total 100.
          minimum: 0
          maximum: 100
          example: 40
    AnalyticsScoringCriterion:
      type: object
      description: A holistic judgement over the whole call.
      required:
        - label
        - description
      properties:
        key:
          type: string
          description: >-
            Stable name this item's results come back under. Optional — omit it
            and InstaView derives a slug of `label` (`Budget confirmed` →
            `budget_confirmed`). Set it when your integration reads the results
            by name: a key you choose survives a later `label` change, a derived
            one does not. If two derived keys collide, the later one gets a
            numeric suffix (`budget`, `budget_2`). Must be unique within its
            list — a duplicate you sent is rejected with `400`, never renamed.
            Reserved names (`__proto__`, `constructor`, `prototype`) are
            rejected. Editing the agent in the visual builder re-derives the key
            from the label.
          maxLength: 64
          pattern: ^[A-Za-z0-9_]{1,64}$
          example: handled_objections
        label:
          type: string
          description: Name of the judgement.
          maxLength: 200
          example: Handled objections
        description:
          type: string
          description: >-
            What a good call looks like for this criterion — what the score is
            judged against.
          maxLength: 1000
          example: Acknowledged the objection and answered it with a concrete example
        importance:
          type: string
          description: >-
            How much a miss matters. `REQUIRED` gates the score; `PREFERRED`
            contributes by weight.
          enum:
            - REQUIRED
            - PREFERRED
          example: PREFERRED
        weight:
          type: number
          description: >-
            Relative contribution to the match score. Weights are relative to
            each other, not a budget that must total 100.
          minimum: 0
          maximum: 100
          example: 40
    AnalyticsOutcome:
      type: object
      description: Something the call was for, decided met / not met afterwards.
      required:
        - label
        - description
      properties:
        key:
          type: string
          description: >-
            Stable name this item's results come back under. Optional — omit it
            and InstaView derives a slug of `label` (`Budget confirmed` →
            `budget_confirmed`). Set it when your integration reads the results
            by name: a key you choose survives a later `label` change, a derived
            one does not. If two derived keys collide, the later one gets a
            numeric suffix (`budget`, `budget_2`). Must be unique within its
            list — a duplicate you sent is rejected with `400`, never renamed.
            Reserved names (`__proto__`, `constructor`, `prototype`) are
            rejected. Editing the agent in the visual builder re-derives the key
            from the label.
          maxLength: 64
          pattern: ^[A-Za-z0-9_]{1,64}$
          example: meeting_booked
        label:
          type: string
          description: Name of the outcome.
          maxLength: 200
          example: Meeting booked
        description:
          type: string
          description: When this counts as achieved, in plain language.
          maxLength: 1000
          example: The contact agreed to a specific date and time
    AnalyticsOutputTag:
      type: object
      description: A label the AI may assign to a call.
      required:
        - label
      properties:
        key:
          type: string
          description: >-
            Stable name this item's results come back under. Optional — omit it
            and InstaView derives a slug of `label` (`Budget confirmed` →
            `budget_confirmed`). Set it when your integration reads the results
            by name: a key you choose survives a later `label` change, a derived
            one does not. If two derived keys collide, the later one gets a
            numeric suffix (`budget`, `budget_2`). Must be unique within its
            list — a duplicate you sent is rejected with `400`, never renamed.
            Reserved names (`__proto__`, `constructor`, `prototype`) are
            rejected. Editing the agent in the visual builder re-derives the key
            from the label.
          maxLength: 64
          pattern: ^[A-Za-z0-9_]{1,64}$
          example: needs_followup
        label:
          type: string
          description: The tag itself.
          maxLength: 200
          example: Needs follow-up
        description:
          type: string
          description: When to apply it.
          maxLength: 1000
          example: The contact asked to be called back
    AnalyticsCapture:
      type: object
      description: >-
        Which qualitative artefacts the after-call pipeline should produce.
        Every flag defaults to `true`.
      properties:
        recording:
          type: boolean
          default: true
          description: Keep the call recording.
        transcript:
          type: boolean
          default: true
          description: Keep the transcript.
        summary:
          type: boolean
          default: true
          description: Produce a call summary.
        qa:
          type: boolean
          default: true
          description: Answer the flow's looping questions from the transcript.
        evaluation:
          type: boolean
          default: true
          description: Produce the strengths / concerns evaluation.
        sentiment:
          type: boolean
          default: true
          description: Produce a sentiment read.
    FlowSequentialBlock:
      type: object
      description: A topic to cover, written as free text.
      required:
        - type
        - prompt
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - sequential
        label:
          type: string
          description: Optional name for this block, shown in the visual builder.
          example: Qualify budget
        prompt:
          type: string
          description: >-
            What the agent should cover here. Supports `{{contact.*}}`
            variables.
          example: Introduce yourself and explain why you are calling.
    FlowLoopingBlock:
      type: object
      description: >-
        A list of questions the agent works through, each with the answer it is
        measured against.
      required:
        - type
        - questions
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - looping
        label:
          type: string
          description: Optional name for this block, shown in the visual builder.
          example: Qualify budget
        questions:
          type: array
          minItems: 1
          maxItems: 50
          items:
            $ref: '#/components/schemas/FlowLoopingQuestion'
    FlowConditionalBlock:
      type: object
      description: >-
        Splits the conversation into routes. The agent takes the branch whose
        condition matches.
      required:
        - type
        - branches
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - conditional
        label:
          type: string
          description: Optional name for this block, shown in the visual builder.
          example: Qualify budget
        branches:
          type: array
          description: Between 2 and 5 routes, evaluated in order.
          minItems: 2
          maxItems: 5
          items:
            $ref: '#/components/schemas/FlowConditionalBranch'
        defaultBranch:
          type: string
          description: >-
            Label of the branch to fall through to when no condition matches.
            Branch ids are assigned by InstaView, so the fallthrough route is
            addressed by label; a label that matches no branch is rejected with
            `400`. Returned on reads as well, so a flow read back can be sent
            again unchanged apart from the assigned ids.
          example: Not now
        defaultBranchId:
          type: string
          format: uuid
          readOnly: true
          description: >-
            The resolved id of the fallthrough branch, assigned by InstaView.
            Read-only: strip it along with the other ids before re-sending a
            flow, and set `defaultBranch` to change the route.
    FlowHumanHandoffBlock:
      type: object
      description: >-
        Transfer the call to a person and end the agent's part of it.


        **PHONE agents only** — an `ONLINE` agent has no call to transfer, and a
        flow carrying this block is rejected with `422`
        (`HUMAN_HANDOFF_NOT_PHONE`).


        **The transfer is final.** InstaView hands the call to the carrier and
        leaves it (a cold transfer), so nothing after this block ever runs — the
        flow's `lastMessage` included. The interview settles as completed, and
        the transcript and analysis cover the agent's part of the call only. A
        step that could never run is rejected rather than stored, so a handoff
        must be the **last block in its own list** (`HUMAN_HANDOFF_NOT_LAST`);
        ending one branch of a `conditional` is fine, since the other branches
        still reach whatever follows it.


        When a flow can reach **more than one** number, every handoff needs a
        `label` and the labels must differ (`HUMAN_HANDOFF_LABEL_REQUIRED`,
        `HUMAN_HANDOFF_LABEL_DUPLICATE`): the agent is offered all destinations
        at once and picks by label, since the number is never in its prompt.
        Handoffs are deduplicated by `phoneNumber`, so two blocks pointing at
        one line are a single destination and may share a label or omit it.


        There is deliberately no fallback number: once the carrier holds the
        call InstaView cannot observe a busy destination, so routing between
        destinations belongs in a `conditional` the agent takes while it is
        still on the call.
      required:
        - type
        - phoneNumber
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        type:
          type: string
          enum:
            - human_handoff
        label:
          type: string
          description: >-
            Optional name for this block, shown in the visual builder. Also
            names the destination for the agent, so a label saying who answers
            the number is worth setting.
          example: Sales
        phoneNumber:
          type: string
          description: >-
            Where to transfer the call, in E.164 format — a leading `+`, country
            code, no spaces or dashes. A number that is not E.164 is rejected
            with `422` (`HUMAN_HANDOFF_INVALID_NUMBER`) when the agent is
            created, not when the transfer is attempted.
          example: '+421900123456'
        message:
          type: string
          description: >-
            What the agent says immediately before transferring. Optional —
            omitted, InstaView supplies a neutral line in the call's language,
            which promises nothing about who answers because the block does not
            know. Supports `{{contact.*}}` variables. An empty string is
            rejected (`HUMAN_HANDOFF_MESSAGE_EMPTY`) rather than read as absent,
            so clearing the field cannot silently restore the default.
          example: I'll put you through to Martin on our sales team now, one moment.
    FlowLoopingQuestion:
      type: object
      required:
        - question
        - idealAnswer
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        question:
          type: string
          description: The question to ask. Supports `{{contact.*}}` variables.
          example: What are you using today?
        idealAnswer:
          type: string
          description: What a good answer looks like. Used when scoring the call.
          example: Names a competing tool
        weight:
          type: number
          description: >-
            Relative importance of this question when scoring. Setting it also
            opts the question into the match score (as `PREFERRED` unless
            `importance` says otherwise).
          minimum: 0
          example: 40
          maximum: 100
        importance:
          type: string
          description: >-
            Opts this question into the agent's match score. Set `importance`
            (or `weight`) to score it; a question with neither is asked but not
            scored. `REQUIRED` gates the score, `PREFERRED` contributes by
            weight.
          enum:
            - REQUIRED
            - PREFERRED
          example: PREFERRED
      description: >-
        A question the agent asks, with the answer it is measured against.
        `importance` and `weight` are how a question joins the match score —
        they live here rather than in `analyticsConfig` because a question is
        addressed by an id InstaView assigns, which a caller cannot know when
        writing the flow.
    FlowConditionalBranch:
      type: object
      required:
        - label
        - condition
        - blocks
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: >-
            Assigned by InstaView. Returned on reads; sending one anywhere in
            the flow is rejected with `400`.
        label:
          type: string
          description: >-
            What this route is — unique within the block, and how
            `defaultBranch` addresses it.
          example: Interested
        condition:
          $ref: '#/components/schemas/FlowBranchCondition'
        blocks:
          type: array
          description: >-
            The sections executed on this route. Conditionals may nest up to 3
            levels deep.
          maxItems: 50
          items:
            $ref: '#/components/schemas/FlowBlock'
    FlowBranchCondition:
      description: How the route is chosen.
      oneOf:
        - $ref: '#/components/schemas/FlowIntentCondition'
        - $ref: '#/components/schemas/FlowExpressionCondition'
      discriminator:
        propertyName: type
        mapping:
          intent:
            $ref: '#/components/schemas/FlowIntentCondition'
          expression:
            $ref: '#/components/schemas/FlowExpressionCondition'
    FlowIntentCondition:
      type: object
      description: Natural-language intent the agent evaluates from the conversation.
      required:
        - type
        - description
      properties:
        type:
          type: string
          enum:
            - intent
        description:
          type: string
          description: The intent to match.
          example: wants to see a demo
    FlowExpressionCondition:
      type: object
      description: Deterministic route on an extracted field.
      required:
        - type
        - field
        - operator
      properties:
        type:
          type: string
          enum:
            - expression
        field:
          type: string
          description: Name of the extracted field to test.
          example: budget
        operator:
          type: string
          enum:
            - EQUALS
            - NOT_EQUALS
            - GREATER_THAN
            - LESS_THAN
            - CONTAINS
            - EXISTS
        value:
          description: >-
            Value to compare against. Required for every operator except EXISTS,
            which ignores it. Use a number for GREATER_THAN and LESS_THAN, and a
            string for CONTAINS.
          example: 1000
        logicalOperator:
          type: string
          description: >-
            Reserved. Nothing composes conditions yet — a branch takes exactly
            one — so this is accepted and ignored.
          enum:
            - AND
            - OR
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: API key for authentication using Bearer scheme

````