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

# Update a content version

> Write steps, start/hide rules, themeId, or type-specific data to a draft version.



## OpenAPI

````yaml /api-reference-v2/openapi.json patch /v2/projects/{projectId}/content/{contentId}/versions/{id}
openapi: 3.0.0
info:
  title: Usertour API v2
  description: >-
    Project-scoped v2 API. Authenticate with a personal API token — an opaque
    `utp_...` string (NOT a JWT: do not try to decode it), created in the
    Usertour app under Settings → API, sent as `Authorization: Bearer utp_...`.
  version: '2.0'
  contact: {}
servers:
  - url: https://api.usertour.io
security: []
tags: []
paths:
  /v2/projects/{projectId}/content/{contentId}/versions/{id}:
    patch:
      tags:
        - Content versions
      summary: Update a content version
      description: >-
        Write steps, start/hide rules, themeId, or type-specific data to a draft
        version.
      operationId: ApiContentVersionsController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Content version ID
          schema:
            type: string
        - name: contentId
          required: true
          in: path
          description: Content ID
          schema:
            type: string
        - name: projectId
          required: true
          in: path
          description: Project ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateVersionBodyDto'
      responses:
        '200':
          description: Updated content version
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentVersionDto'
        '400':
          description: >-
            Invalid request — E1017 validation (may carry `issues`; an invalid
            orderBy/limit is also E1017), E1015 invalid scope, E0003 invalid
            against current domain state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '401':
          description: Missing or expired API key — E1010, E1020.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '403':
          description: >-
            Refused — E1000 invalid key, E1011 project not in token scope, E1012
            insufficient scope, E1029 environment not in token scope, E1032
            environment creation needs a token without env-targeted capabilities
            (its allowlist cannot cover a not-yet-existing environment).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '404':
          description: Content version not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '409':
          description: >-
            E0049 the version is published (read-only — fork an editable draft
            first), or E0050 it was modified concurrently (re-read and retry).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded — E1013. The limit follows the project's plan
            (100/500/1000/3000 requests per minute); unknown credentials share a
            per-IP bucket. Every response also carries X-RateLimit-Limit /
            -Remaining / -Reset for pacing; a 429 adds the standard Retry-After
            header (seconds to back off).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponseDto'
      security:
        - bearer: []
components:
  schemas:
    UpdateVersionBodyDto:
      type: object
      properties:
        steps:
          type: array
          items:
            type: object
            properties:
              id:
                description: >-
                  Primary id of an existing step to update in place. It is
                  regenerated when you fork a version, so for edits that must
                  survive a fork prefer `cvid`.
                type: string
              cvid:
                description: >-
                  Stable step handle that survives forking: echo it to update an
                  existing step in place without re-reading new ids. A step is
                  matched by `id` first, then `cvid`; omit both to create a new
                  step.
                type: string
              key:
                description: >-
                  Optional author-chosen handle for wiring "go to step" actions
                  within this request (unique among the steps you send). A
                  button action can set `step` to this key to target this step
                  even before it exists. Write-only — not stored, not returned
                  on read.
                type: string
              name:
                type: string
              type:
                type: string
                enum:
                  - tooltip
                  - modal
                  - hidden
                  - bubble
                description: >-
                  Step kind. Only `tooltip` anchors to a target element; the
                  rest are page-level.
              sequence:
                type: number
              themeId:
                type: string
                description: >-
                  Per-step theme override. Omit to keep the current value; set
                  to a theme id (from the themes list) to override; set to null
                  to clear and inherit the flow theme.
                nullable: true
              target:
                type: object
                properties:
                  selector:
                    type: string
                    minLength: 1
                    description: >-
                      A stable CSS selector for the element. The runtime targets
                      the FIRST match — so either make the selector unique, or
                      pair a stable non-unique selector with `nth` to pick the
                      intended match. A non-unique selector with no `nth`
                      targets the first (often wrong) element and the tooltip
                      silently won't render.
                  text:
                    description: >-
                      Optional refinement of `selector`. Requires the targeted
                      element's visible text to equal this (exact match, after
                      trim) — use it to pin a specific content/state (e.g. a
                      stable id whose displayed text you want to match: id +
                      text). It refines the element chosen by `selector`/`nth`;
                      on its own it does NOT search among multiple matches, so
                      disambiguate a non-unique selector with `nth`, not `text`
                      alone.
                    type: string
                  nth:
                    description: >-
                      Optional refinement of `selector`. 0-based index to pick
                      which match when the selector isn't unique — e.g. a stable
                      selector matching 3 elements + `nth: 1` targets the 2nd,
                      giving a unique result. Matches are taken in document
                      order (as they appear in the page HTML). Range 0–4 — only
                      the first 5 matches are addressable; a larger value is
                      rejected.
                    type: integer
                    minimum: 0
                    maximum: 4
                required:
                  - selector
              placement:
                anyOf:
                  - type: object
                    properties:
                      side:
                        description: >-
                          Which side of the target the tooltip sits on. OMIT
                          side+align to auto-position (the tooltip picks a spot
                          and flips to avoid the viewport edge — best when you
                          can't see the element). Setting side (or align) pins
                          that direction: the tooltip renders exactly there and
                          no longer auto-flips, so only pin when the element is
                          not near a screen edge. When READING a step back,
                          check `alignType` first: under `auto` the side/align
                          you see are just the auto starting position, not a
                          pin.
                        type: string
                        enum:
                          - top
                          - right
                          - bottom
                          - left
                      align:
                        description: Alignment along the side. See `side`.
                        type: string
                        enum:
                          - start
                          - center
                          - end
                      sideOffset:
                        description: >-
                          Pixels between the target and the tooltip, along
                          `side`.
                        type: number
                      alignOffset:
                        description: >-
                          Pixel shift along the alignment axis. Only applies
                          when `align` is `start` or `end` — at `center`
                          alignment the runtime ignores it silently.
                        type: number
                      alignType:
                        description: >-
                          Position mode. `auto` auto-positions and flips to
                          avoid the viewport edge (ignoring side/align); `fixed`
                          pins to side/align without flipping. Usually omit it:
                          providing side/align implies `fixed`, and omitting
                          them implies `auto`. Set it only to override that
                          (e.g. `auto` while still passing a side/align you want
                          ignored). Read-backs always carry concrete side/align
                          even in `auto` mode (the auto starting position,
                          bottom/center) — `alignType` is what governs, and
                          `auto` still flips at runtime.
                        type: string
                        enum:
                          - auto
                          - fixed
                      backdrop:
                        description: Dim the rest of the page while this tooltip is up.
                        type: boolean
                      blockTarget:
                        description: >-
                          Make the backdrop swallow clicks on the highlighted
                          element, so the user must use the tooltip. REQUIRES
                          `backdrop: true` — on its own it does nothing (the
                          renderer only consults it inside the backdrop branch).
                        type: boolean
                    additionalProperties: false
                  - type: object
                    properties:
                      position:
                        type: string
                        enum:
                          - leftTop
                          - centerTop
                          - rightTop
                          - leftCenter
                          - center
                          - rightCenter
                          - leftBottom
                          - centerBottom
                          - rightBottom
                      offsetX:
                        description: >-
                          Pixel shift from the grid cell. Applies in every cell
                          EXCEPT `position: "center"`, where both offsets are
                          ignored silently.
                        type: number
                      offsetY:
                        description: See `offsetX`.
                        type: number
                      backdrop:
                        type: boolean
                    required:
                      - position
                    additionalProperties: false
                description: >-
                  Two placement shapes, by step kind: a TOOLTIP (anchored to a
                  `target`) uses `{ side, align, sideOffset?, alignOffset?,
                  alignType? }` positioned relative to the element; a MODAL uses
                  `{ position, offsetX?, offsetY? }` on a 9-cell viewport grid
                  (e.g. `"center"`). Both may set `backdrop`; `blockTarget` is
                  TOOLTIP-ONLY (a modal already covers the page) and
                  additionally requires `backdrop: true` — it makes the backdrop
                  swallow clicks on the highlighted element. A BUBBLE step is
                  positioned by its THEME's bubble placement, so the only key it
                  accepts here is `{ backdrop }` (positional keys are rejected —
                  move the bubble by changing the theme); a HIDDEN step renders
                  no UI and rejects `placement` entirely.
              width:
                description: >-
                  Step width in pixels — OVERRIDES the theme's surface width
                  (tooltip.width / modal.width / bubble.width) for THIS step
                  only; omit to use the theme width. Widths are border-box: the
                  outer edge renders at exactly this value (border inside); the
                  inner iframe measures 2x the theme border width less.
                type: number
              skippable:
                type: boolean
              explicitCompletionStep:
                description: >-
                  Marks this step as an explicit completion point — reaching it
                  completes the flow.
                type: boolean
              content:
                description: >-
                  The step's body blocks. On an ECHOED step (matched by
                  cvid/id), omit to keep the stored content unchanged — an
                  explicit [] clears it. Same omit-keeps semantics as
                  `triggers`.
                type: array
                items:
                  $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
              triggers:
                type: array
                items:
                  type: object
                  properties:
                    when:
                      description: >-
                        REACTIVE slot — polled live in the browser while the
                        step is on screen, so it accepts only client-evaluable
                        condition types: attribute / current_url / element /
                        text_input / text_filled / time_window. Event / segment
                        / content_state conditions are server-evaluated and
                        rejected here (E1017). A trigger with NO `when` never
                        fires (an empty set is "not matched", not "always").
                      type: array
                      items:
                        $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
                    do:
                      type: array
                      items:
                        oneOf:
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - goto_step
                              step:
                                type: string
                                description: >-
                                  Target step: a step `key` declared elsewhere
                                  in the same write, or an existing step cvid.
                                  Resolved server-side to the cvid.
                            required:
                              - type
                              - step
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - start_content
                              content:
                                type: string
                                description: >-
                                  contentId of the flow or checklist to launch
                                  (an id from the content list) — a raw content
                                  id, NOT a step key (unlike goto_step). Must
                                  reference a flow or checklist (a banner /
                                  launcher / resource-center / tracker is
                                  rejected at write). The target must be
                                  PUBLISHED to actually start at runtime; an
                                  unknown/dangling id is rejected at validate.
                              step:
                                description: >-
                                  Optional cvid of a step within the launched
                                  flow to start at.
                                type: string
                            required:
                              - type
                              - content
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - navigate
                              url:
                                type: string
                                description: >-
                                  Absolute URL, or an app-relative path
                                  ("/docs/x") resolved against the origin the
                                  user is on — relative paths are the normal
                                  choice for in-app navigation.
                              newTab:
                                description: >-
                                  Open the URL in a new browser tab instead of
                                  navigating the current one.
                                type: boolean
                            required:
                              - type
                              - url
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - dismiss
                            required:
                              - type
                            description: >-
                              Dismiss the piece the action lives on. NOT
                              accepted everywhere this union appears: a resource
                              center has no dismiss (closing the panel is a UI
                              affordance, not an action) and an announcement is
                              marked seen, never dismissed — writes there are
                              rejected (E1017), not ignored. Flows / checklists
                              / launchers / banners all accept it.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - run_javascript
                              script:
                                type: string
                            required:
                              - type
                              - script
                            description: >-
                              Read-back of an existing script action — scripts
                              are not authorable through this API. Echo it back
                              UNCHANGED (same script) when rewriting the
                              surrounding list and the stored action is
                              preserved; omitting it deletes it (action lists
                              are full replacements). Authoring a new or edited
                              script is rejected.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - unsupported
                              note:
                                type: string
                            required:
                              - type
                            description: >-
                              Echo-only placeholder for a stored action this
                              schema cannot express (`note` = internal type).
                              Echo it back to preserve the stored action;
                              writing one fresh is rejected.
                    waitSeconds:
                      description: >-
                        Delay in SECONDS between the `when` conditions matching
                        and the `do` actions firing. The timer arms the first
                        time `when` matches and the actions fire after the wait
                        EVEN IF the conditions have since stopped matching (the
                        match is latched, not re-checked). Capped at 300 seconds
                        by the runtime (a larger value is clamped).
                      type: number
                  required:
                    - do
              onClick:
                description: >-
                  Actions to run when the user clicks the step's TARGET ELEMENT
                  on the page (click-to-advance) — distinct from a `button`
                  block, whose actions fire on a button rendered inside the
                  step. `tooltip` steps only (the other kinds have no target
                  element); sending it on a modal / bubble / hidden step is
                  rejected.
                type: array
                items:
                  oneOf:
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - goto_step
                        step:
                          type: string
                          description: >-
                            Target step: a step `key` declared elsewhere in the
                            same write, or an existing step cvid. Resolved
                            server-side to the cvid.
                      required:
                        - type
                        - step
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - start_content
                        content:
                          type: string
                          description: >-
                            contentId of the flow or checklist to launch (an id
                            from the content list) — a raw content id, NOT a
                            step key (unlike goto_step). Must reference a flow
                            or checklist (a banner / launcher / resource-center
                            / tracker is rejected at write). The target must be
                            PUBLISHED to actually start at runtime; an
                            unknown/dangling id is rejected at validate.
                        step:
                          description: >-
                            Optional cvid of a step within the launched flow to
                            start at.
                          type: string
                      required:
                        - type
                        - content
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - navigate
                        url:
                          type: string
                          description: >-
                            Absolute URL, or an app-relative path ("/docs/x")
                            resolved against the origin the user is on —
                            relative paths are the normal choice for in-app
                            navigation.
                        newTab:
                          description: >-
                            Open the URL in a new browser tab instead of
                            navigating the current one.
                          type: boolean
                      required:
                        - type
                        - url
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - dismiss
                      required:
                        - type
                      description: >-
                        Dismiss the piece the action lives on. NOT accepted
                        everywhere this union appears: a resource center has no
                        dismiss (closing the panel is a UI affordance, not an
                        action) and an announcement is marked seen, never
                        dismissed — writes there are rejected (E1017), not
                        ignored. Flows / checklists / launchers / banners all
                        accept it.
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - run_javascript
                        script:
                          type: string
                      required:
                        - type
                        - script
                      description: >-
                        Read-back of an existing script action — scripts are not
                        authorable through this API. Echo it back UNCHANGED
                        (same script) when rewriting the surrounding list and
                        the stored action is preserved; omitting it deletes it
                        (action lists are full replacements). Authoring a new or
                        edited script is rejected.
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - unsupported
                        note:
                          type: string
                      required:
                        - type
                      description: >-
                        Echo-only placeholder for a stored action this schema
                        cannot express (`note` = internal type). Echo it back to
                        preserve the stored action; writing one fresh is
                        rejected.
            required:
              - name
              - type
        startRules:
          type: object
          properties:
            when:
              description: >-
                Start conditions (full replacement when present). Omit to keep
                the existing conditions and change only the settings.
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
            frequency:
              description: >-
                How often the content may auto-start (flow/checklist only). Left
                unset on a write, the builder default (`once`) is seeded and
                STORED — read-backs show the effective mode explicitly. A
                version stored with NO frequency at all (reachable only through
                legacy/builder-external writes, never through this API) runs
                with NO limit: it starts again every time its rules match once
                the prior session ends — validate_content_version warns on that
                state.
              type: object
              properties:
                mode:
                  type: string
                  enum:
                    - once
                    - multiple
                    - unlimited
                  description: >-
                    once = show a single time; multiple = up to N times per
                    window; unlimited = every time the conditions match (subject
                    to `every`).
                every:
                  description: >-
                    Re-show window. Used by `multiple` (with `times`) and
                    `unlimited`; ignored for `once`. If omitted for those modes
                    a default window is applied. Manual and programmatic starts
                    also count toward the `multiple` limit.
                  type: object
                  properties:
                    times:
                      type: number
                    duration:
                      type: number
                    unit:
                      type: string
                      enum:
                        - seconds
                        - minutes
                        - hours
                        - days
                  required:
                    - duration
                    - unit
                atLeast:
                  description: >-
                    Only auto-start if no OTHER content of the SAME type has
                    been shown within this window — and since only flows accept
                    this knob, in practice: no other FLOW. A banner / checklist
                    / launcher showing does NOT block it. Avoids stacking
                    several flows on a user at once.
                  type: object
                  properties:
                    duration:
                      type: number
                    unit:
                      type: string
                      enum:
                        - seconds
                        - minutes
                        - hours
                        - days
                  required:
                    - duration
                    - unit
              required:
                - mode
            priority:
              description: >-
                Tie-breaker when a user matches the start conditions for more
                than one piece of content at the same time — the higher priority
                starts first. Content with no priority set ranks as `medium`.
              type: string
              enum:
                - highest
                - high
                - medium
                - low
                - lowest
            waitSeconds:
              description: >-
                Delay in SECONDS between the start conditions matching and the
                content becoming ELIGIBLE to start. The countdown itself
                survives the conditions un-matching mid-wait, but unlike a
                trigger wait (which fires its actions regardless), an elapsed
                start-rule wait guarantees nothing: the conditions are
                RE-CHECKED at show time, and the content starts at the next
                moment they match again. One exception: when a session of the
                same content type starts or ends mid-wait, in-flight timers are
                cancelled and re-armed — a still-matching version then restarts
                its wait from zero. Capped at 300 seconds by the runtime (a
                larger value is clamped).
              type: number
            startIfNotComplete:
              description: >-
                When true, this content won't auto-start for users who have
                already completed it.
              type: boolean
          description: >-
            PATCHES the stored rules field-by-field: an omitted setting
            (frequency / priority / waitSeconds / startIfNotComplete) keeps its
            stored value — including one inherited from the forked version — so
            to turn a setting off, send it explicitly (e.g. `startIfNotComplete:
            false`). `when`, when present, fully replaces the condition list.
            `null` clears the rules entirely (content stops auto-starting).
            Which settings and which `when` condition types the CONTENT TYPE
            supports varies (e.g. no priority on a launcher,
            attribute/segment-only targeting on an announcement) — unsupported
            ones are rejected per type.
          nullable: true
        hideRules:
          type: object
          properties:
            when:
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
          required:
            - when
          description: >-
            Temporarily-hide rules. Only some content types support them
            (rejected per type).
          nullable: true
        themeId:
          description: Theme to apply (cannot be cleared).
          type: string
        data:
          description: >-
            Type-specific body for a non-flow content version: checklist /
            launcher / banner / tracker / announcement / resource-center.
            Field-level merged onto the existing data.
          anyOf:
            - type: object
              properties:
                buttonText:
                  description: >-
                    Label on the collapsed checklist launcher pill (e.g.
                    "Getting started"). Plain string — NO `{{ }}` interpolation
                    (braces would render literally).
                  type: string
                initialDisplay:
                  description: >-
                    How the checklist first appears: `expanded` shows the whole
                    checklist (tasks and all); `button` shows just the launcher
                    button.
                  type: string
                  enum:
                    - expanded
                    - button
                completionOrder:
                  description: >-
                    Whether tasks can be completed in `any` order, or must be
                    completed `ordered` (top to bottom among the tasks the user
                    can currently SEE — a task hidden by `onlyShowWhen` does not
                    block the ones after it). This is the ONLY built-in
                    cross-task sequencing — there is no per-task "after task X"
                    condition; for finer dependencies gate a task's
                    `onlyShowWhen` on the shared event/state that completes its
                    prerequisite.
                  type: string
                  enum:
                    - any
                    - ordered
                preventDismiss:
                  description: When true, users can't dismiss the checklist.
                  type: boolean
                autoDismiss:
                  description: >-
                    When true, the checklist closes on its own once every task
                    is done.
                  type: boolean
                content:
                  description: >-
                    Rich content shown at the top of the expanded panel, above
                    the task list — typically a short welcome line framing what
                    the tasks achieve.
                  type: array
                  items:
                    $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                items:
                  description: >-
                    The checklist tasks. To be usable (enforced at publish) each
                    item needs a `name` AND at least one of `completeWhen` (how
                    it auto-completes) or `clickActions` (what its row does) —
                    an item with neither is a dead row. `task_clicked` in
                    `completeWhen` is the only completion that needs no app
                    instrumentation.
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        description: >-
                          Server-owned task identity — ECHO it back when
                          rewriting `items`. An item written without its
                          existing id gets a NEW one: in-flight users'
                          completion state for it resets and its per-task
                          analytics rows break. Omit only for a genuinely new
                          task.
                        type: string
                      name:
                        type: string
                        description: >-
                          The visible task row label. Plain string — NO `{{ }}`
                          interpolation (braces would render literally).
                      description:
                        description: >-
                          Optional supporting text rendered below the task name.
                          A short benefit statement or time estimate ("Send an
                          invite so your team can collaborate", "~30 sec")
                          measurably lifts task click-through — prefer setting
                          it over leaving the row name-only. Plain string — NO
                          `{{ }}` interpolation (braces would render literally).
                        type: string
                      completeWhen:
                        default: []
                        description: >-
                          Condition(s) that mark THIS task done. Use [{ "type":
                          "task_clicked" }] to complete it when the user clicks
                          the task — the only option that needs no app
                          instrumentation; other conditions (event / element /
                          segment / current_url / attribute) require the
                          matching wiring or data in your app. Empty = the task
                          never auto-completes.
                        type: array
                        items:
                          $ref: '#/components/schemas/UpdateVersionBodyDto__schema3'
                      clickActions:
                        default: []
                        description: >-
                          What happens when the user CLICKS the task row (e.g.
                          [{ "type": "navigate", "url": "/x" }]) — a side
                          effect, NOT completion. To also mark the task done on
                          that click, add { "type": "task_clicked" } to
                          completeWhen.
                        type: array
                        items:
                          oneOf:
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - goto_step
                                step:
                                  type: string
                                  description: >-
                                    Target step: a step `key` declared elsewhere
                                    in the same write, or an existing step cvid.
                                    Resolved server-side to the cvid.
                              required:
                                - type
                                - step
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - start_content
                                content:
                                  type: string
                                  description: >-
                                    contentId of the flow or checklist to launch
                                    (an id from the content list) — a raw
                                    content id, NOT a step key (unlike
                                    goto_step). Must reference a flow or
                                    checklist (a banner / launcher /
                                    resource-center / tracker is rejected at
                                    write). The target must be PUBLISHED to
                                    actually start at runtime; an
                                    unknown/dangling id is rejected at validate.
                                step:
                                  description: >-
                                    Optional cvid of a step within the launched
                                    flow to start at.
                                  type: string
                              required:
                                - type
                                - content
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - navigate
                                url:
                                  type: string
                                  description: >-
                                    Absolute URL, or an app-relative path
                                    ("/docs/x") resolved against the origin the
                                    user is on — relative paths are the normal
                                    choice for in-app navigation.
                                newTab:
                                  description: >-
                                    Open the URL in a new browser tab instead of
                                    navigating the current one.
                                  type: boolean
                              required:
                                - type
                                - url
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - dismiss
                              required:
                                - type
                              description: >-
                                Dismiss the piece the action lives on. NOT
                                accepted everywhere this union appears: a
                                resource center has no dismiss (closing the
                                panel is a UI affordance, not an action) and an
                                announcement is marked seen, never dismissed —
                                writes there are rejected (E1017), not ignored.
                                Flows / checklists / launchers / banners all
                                accept it.
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - run_javascript
                                script:
                                  type: string
                              required:
                                - type
                                - script
                              description: >-
                                Read-back of an existing script action — scripts
                                are not authorable through this API. Echo it
                                back UNCHANGED (same script) when rewriting the
                                surrounding list and the stored action is
                                preserved; omitting it deletes it (action lists
                                are full replacements). Authoring a new or
                                edited script is rejected.
                            - type: object
                              properties:
                                type:
                                  type: string
                                  enum:
                                    - unsupported
                                note:
                                  type: string
                              required:
                                - type
                              description: >-
                                Echo-only placeholder for a stored action this
                                schema cannot express (`note` = internal type).
                                Echo it back to preserve the stored action;
                                writing one fresh is rejected.
                      onlyShowWhen:
                        description: >-
                          Condition(s) that gate whether this task is VISIBLE
                          (distinct from `completeWhen`, which marks it done).
                          Omit = always shown. There is no "task X is completed"
                          condition, so to make this task appear only after
                          another is done, gate on the same event/state that
                          completes that other task — you cannot reference
                          another task directly.
                        type: array
                        items:
                          $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
                    required:
                      - name
                    additionalProperties: false
              additionalProperties: {}
            - type: object
              properties:
                style:
                  description: >-
                    Visual form: `beacon` = pulsing dot, `icon` = a static icon
                    (see `icon`), `button` = a text button (see `buttonText`),
                    `hidden` = no visual — interactions on the target element
                    itself drive `behavior`.
                  type: string
                  enum:
                    - beacon
                    - icon
                    - hidden
                    - button
                icon:
                  type: object
                  properties:
                    source:
                      description: >-
                        Where the icon comes from: `builtin` uses `type` (a
                        RemixIcon name), `upload`/`url` use `url`. A launcher
                        always renders an icon — there is no `none` / `inherit`
                        here (the resource-center block icons are a different
                        field and DO support them); to keep a launcher off the
                        page, gate it with start rules instead.
                      type: string
                      enum:
                        - builtin
                        - upload
                        - url
                    url:
                      description: >-
                        Image URL for the icon — only used when source is
                        'upload' or 'url'.
                      type: string
                    type:
                      description: >-
                        Builtin icon name (when source='builtin'): a RemixIcon
                        name in kebab `-line`/`-fill` style — e.g. `home-line`,
                        `question-line`, `rocket`. NOT lucide names
                        (`help-circle` / `sparkles` / `book-open`): a name
                        outside the registry is rejected by validate/publish
                        with the bad name spelled out (it would render nothing).
                        Common names + an intent→name table are in the MCP
                        authoring guide (icons section).
                      type: string
                buttonText:
                  description: >-
                    Label of the button — only rendered when style is 'button'.
                    Plain string — NO `{{ }}` interpolation.
                  type: string
                target:
                  description: >-
                    The page element the launcher anchors to (selector + beacon
                    placement on it).
                  type: object
                  properties:
                    selector:
                      type: string
                      minLength: 1
                      description: >-
                        A stable CSS selector for the element. The runtime
                        targets the FIRST match — so either make the selector
                        unique, or pair a stable non-unique selector with `nth`
                        to pick the intended match. A non-unique selector with
                        no `nth` targets the first (often wrong) element and the
                        tooltip silently won't render.
                    text:
                      description: >-
                        Optional refinement of `selector`. Requires the targeted
                        element's visible text to equal this (exact match, after
                        trim) — use it to pin a specific content/state (e.g. a
                        stable id whose displayed text you want to match: id +
                        text). It refines the element chosen by
                        `selector`/`nth`; on its own it does NOT search among
                        multiple matches, so disambiguate a non-unique selector
                        with `nth`, not `text` alone.
                      type: string
                    nth:
                      description: >-
                        Optional refinement of `selector`. 0-based index to pick
                        which match when the selector isn't unique — e.g. a
                        stable selector matching 3 elements + `nth: 1` targets
                        the 2nd, giving a unique result. Matches are taken in
                        document order (as they appear in the page HTML). Range
                        0–4 — only the first 5 matches are addressable; a larger
                        value is rejected.
                      type: integer
                      minimum: 0
                      maximum: 4
                    placement:
                      description: >-
                        Where the beacon sits relative to its target element.
                        Omit to center it on the target. (The tooltip has its
                        own `tooltip.placement`; this positions the launcher
                        itself.) Read back ONLY when a side/align is pinned — an
                        auto-centered beacon omits it.
                      type: object
                      properties:
                        side:
                          description: >-
                            Which side of the target the beacon sits on. OMIT
                            side+align to center the beacon on the target (with
                            viewport-edge flipping); setting side (or align)
                            pins it there.
                          type: string
                          enum:
                            - top
                            - right
                            - bottom
                            - left
                        align:
                          description: Alignment along the side. See `side`.
                          type: string
                          enum:
                            - start
                            - center
                            - end
                        sideOffset:
                          description: >-
                            Gap in pixels between the beacon and the target
                            edge, along `side`.
                          type: number
                        alignOffset:
                          description: >-
                            Pixel shift along the alignment axis. Only applies
                            when `align` is `start`/`end` — at `center` (or
                            under `auto`) the runtime ignores it.
                          type: number
                        alignType:
                          description: >-
                            Position mode. `auto` centers on the target and
                            flips at the viewport edge (ignoring side/align);
                            `fixed` pins to side/align. Providing side/align
                            implies `fixed`, omitting them implies `auto` — so
                            leave `auto` and the beacon centers regardless of
                            `align`.
                          type: string
                          enum:
                            - auto
                            - fixed
                  required:
                    - selector
                zIndex:
                  description: >-
                    Stacking order (CSS z-index). Integer; negative values are
                    allowed. Omit to use the SDK's default stacking.
                  type: integer
                  minimum: -9007199254740991
                  maximum: 9007199254740991
                tooltip:
                  type: object
                  properties:
                    placement:
                      description: >-
                        Where the tooltip opens relative to its anchor (see
                        `reference`).
                      type: object
                      properties:
                        side:
                          description: >-
                            Which side of the target the tooltip opens on. OMIT
                            side+align to auto-position (picks a spot + flips to
                            avoid the viewport edge); setting side (or align)
                            pins that direction (no auto-flip). Same auto/fixed
                            derivation as a flow tooltip.
                          type: string
                          enum:
                            - top
                            - right
                            - bottom
                            - left
                        align:
                          description: Alignment along the side. See `side`.
                          type: string
                          enum:
                            - start
                            - center
                            - end
                        sideOffset:
                          description: >-
                            Gap in pixels between the tooltip and its anchor,
                            along `side`.
                          type: number
                        alignOffset:
                          description: >-
                            Pixel shift along the alignment axis. Only applies
                            when `align` is `start`/`end`.
                          type: number
                        alignType:
                          description: >-
                            Position mode. `auto` auto-positions + flips
                            (ignoring side/align); `fixed` pins to side/align.
                            Usually omit — providing side/align implies `fixed`,
                            omitting them implies `auto`. Without this, an
                            `auto` launcher renders center and your `align` is
                            ignored.
                          type: string
                          enum:
                            - auto
                            - fixed
                    width:
                      description: >-
                        Tooltip width in pixels. Omit to use the theme's
                        tooltip.width.
                      type: number
                    reference:
                      description: >-
                        Whether the tooltip anchors to the target element or to
                        the launcher itself.
                      type: string
                      enum:
                        - target
                        - launcher
                    content:
                      type: array
                      items:
                        $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                    settings:
                      type: object
                      properties:
                        dismissAfterFirstActivation:
                          description: >-
                            Dismiss the launcher after its tooltip is first
                            shown and closed.
                          type: boolean
                        keepOpenWhenHovered:
                          description: >-
                            READ-ONLY — not wired at runtime: the tooltip ALWAYS
                            stays open while hovered regardless of this value.
                            Echoed for round-trip; changing it is rejected.
                          type: boolean
                        hideLauncherWhenTooltipShown:
                          description: >-
                            READ-ONLY — not wired at runtime: the launcher is
                            NEVER hidden while its tooltip shows. Echoed for
                            round-trip; changing it is rejected.
                          type: boolean
                behavior:
                  description: >-
                    How users interact with the launcher and what that
                    interaction does. Omit for the default (click the launcher
                    to show the tooltip).
                  type: object
                  properties:
                    triggerElement:
                      description: >-
                        Which element listens for the interaction: the launcher
                        visual, the target element itself, or either. With style
                        'hidden' the target is the only thing to interact with.
                      type: string
                      enum:
                        - launcher
                        - target
                        - target-or-launcher
                    event:
                      description: >-
                        The interaction that triggers the launcher: click or
                        hover.
                      type: string
                      enum:
                        - clicked
                        - hovered
                    action:
                      description: >-
                        What the interaction does: 'show-tooltip' opens
                        `tooltip.content`; 'perform-action' runs `actions`
                        directly (e.g. start a flow) with no tooltip.
                      type: string
                      enum:
                        - show-tooltip
                        - perform-action
                    actions:
                      description: >-
                        The action list run when action is 'perform-action'
                        (e.g. [{ "type": "start_content", "content": "<flowId>"
                        }]). Ignored under 'show-tooltip' — put button actions
                        inside the tooltip content instead.
                      type: array
                      items:
                        oneOf:
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - goto_step
                              step:
                                type: string
                                description: >-
                                  Target step: a step `key` declared elsewhere
                                  in the same write, or an existing step cvid.
                                  Resolved server-side to the cvid.
                            required:
                              - type
                              - step
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - start_content
                              content:
                                type: string
                                description: >-
                                  contentId of the flow or checklist to launch
                                  (an id from the content list) — a raw content
                                  id, NOT a step key (unlike goto_step). Must
                                  reference a flow or checklist (a banner /
                                  launcher / resource-center / tracker is
                                  rejected at write). The target must be
                                  PUBLISHED to actually start at runtime; an
                                  unknown/dangling id is rejected at validate.
                              step:
                                description: >-
                                  Optional cvid of a step within the launched
                                  flow to start at.
                                type: string
                            required:
                              - type
                              - content
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - navigate
                              url:
                                type: string
                                description: >-
                                  Absolute URL, or an app-relative path
                                  ("/docs/x") resolved against the origin the
                                  user is on — relative paths are the normal
                                  choice for in-app navigation.
                              newTab:
                                description: >-
                                  Open the URL in a new browser tab instead of
                                  navigating the current one.
                                type: boolean
                            required:
                              - type
                              - url
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - dismiss
                            required:
                              - type
                            description: >-
                              Dismiss the piece the action lives on. NOT
                              accepted everywhere this union appears: a resource
                              center has no dismiss (closing the panel is a UI
                              affordance, not an action) and an announcement is
                              marked seen, never dismissed — writes there are
                              rejected (E1017), not ignored. Flows / checklists
                              / launchers / banners all accept it.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - run_javascript
                              script:
                                type: string
                            required:
                              - type
                              - script
                            description: >-
                              Read-back of an existing script action — scripts
                              are not authorable through this API. Echo it back
                              UNCHANGED (same script) when rewriting the
                              surrounding list and the stored action is
                              preserved; omitting it deletes it (action lists
                              are full replacements). Authoring a new or edited
                              script is rejected.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - unsupported
                              note:
                                type: string
                            required:
                              - type
                            description: >-
                              Echo-only placeholder for a stored action this
                              schema cannot express (`note` = internal type).
                              Echo it back to preserve the stored action;
                              writing one fresh is rejected.
              additionalProperties: {}
            - type: object
              properties:
                placement:
                  description: >-
                    Where the banner shows: the top/bottom of the page, or
                    relative to a container element (top/bottom of it, or
                    immediately before/after it). The container/element variants
                    require `containerTarget`.
                  type: string
                  enum:
                    - top-of-page
                    - bottom-of-page
                    - top-of-container-element
                    - bottom-of-container-element
                    - immediately-before-element
                    - immediately-after-element
                content:
                  type: array
                  items:
                    $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                zIndex:
                  description: >-
                    Stacking order (CSS z-index). Integer; negative values are
                    allowed. Omit to use the SDK's default stacking.
                  type: integer
                  minimum: -9007199254740991
                  maximum: 9007199254740991
                settings:
                  type: object
                  properties:
                    overlayOverAppContent:
                      description: >-
                        When true the banner floats over the page; when false it
                        takes its own space and pushes the page content down.
                        Push mode only displaces normal-flow content — the host
                        app's `position: fixed` bars (top nav, sidebars) do NOT
                        move and will overlap the banner. For such apps, either
                        float the banner over the content (true), or use a
                        container/element-relative `placement` so the banner
                        lives inside the scrolling content area instead of
                        fighting the fixed bars. Floating alone does NOT keep
                        the banner on screen — it still scrolls away with the
                        page (CSS absolute); pair it with `stickToTop` for the
                        always-visible floating bar (see the 2x2 there).
                      type: boolean
                    stickToTop:
                      description: >-
                        Pins the banner to the viewport edge while the user
                        scrolls — the EDGE follows `placement`, despite the
                        name: top variants pin to the top, bottom variants to
                        the BOTTOM. Combines with `overlayOverAppContent` into
                        four modes (CSS position): neither = in-flow, scrolls
                        away with the page (the default); stick only = keeps its
                        own space and pins (sticky); overlay only = floats but
                        STILL scrolls away (absolute); both = floats and stays
                        pinned (fixed) — the classic always-visible bar. So for
                        "visible while scrolling", set this true regardless of
                        overlay.
                      type: boolean
                    allowDismiss:
                      description: >-
                        Adds an X button so the user can permanently dismiss the
                        banner.
                      type: boolean
                    animateOnAppear:
                      description: Slide the banner in instead of popping into place.
                      type: boolean
                containerTarget:
                  description: >-
                    The anchor element for the container/element-relative
                    `placement` variants (top/bottom of it, or immediately
                    before/after it). Required by those placements; ignored for
                    top/bottom-of-page.
                  type: object
                  properties:
                    selector:
                      type: string
                      minLength: 1
                      description: >-
                        A stable CSS selector for the element. The runtime
                        targets the FIRST match — so either make the selector
                        unique, or pair a stable non-unique selector with `nth`
                        to pick the intended match. A non-unique selector with
                        no `nth` targets the first (often wrong) element and the
                        tooltip silently won't render.
                    text:
                      description: >-
                        Optional refinement of `selector`. Requires the targeted
                        element's visible text to equal this (exact match, after
                        trim) — use it to pin a specific content/state (e.g. a
                        stable id whose displayed text you want to match: id +
                        text). It refines the element chosen by
                        `selector`/`nth`; on its own it does NOT search among
                        multiple matches, so disambiguate a non-unique selector
                        with `nth`, not `text` alone.
                      type: string
                    nth:
                      description: >-
                        Optional refinement of `selector`. 0-based index to pick
                        which match when the selector isn't unique — e.g. a
                        stable selector matching 3 elements + `nth: 1` targets
                        the 2nd, giving a unique result. Matches are taken in
                        document order (as they appear in the page HTML). Range
                        0–4 — only the first 5 matches are addressable; a larger
                        value is rejected.
                      type: integer
                      minimum: 0
                      maximum: 4
                  required:
                    - selector
                layout:
                  type: object
                  properties:
                    maxContentWidth:
                      description: >-
                        Max width of the banner content, in pixels. Omit for no
                        limit.
                      type: number
                    maxEmbedWidth:
                      description: >-
                        Max width of the embed container, in pixels. Omit for no
                        limit.
                      type: number
                    borderRadius:
                      description: Corner rounding in pixels. Omit for the theme default.
                      type: number
                    outerMargin:
                      description: Space (in pixels) around the banner on all four sides.
                      type: object
                      properties:
                        top:
                          type: number
                        right:
                          type: number
                        bottom:
                          type: number
                        left:
                          type: number
                      required:
                        - top
                        - right
                        - bottom
                        - left
              additionalProperties: {}
            - type: object
              properties:
                event:
                  type: string
                  description: >-
                    The CUSTOM event this tracker fires when its startRules
                    match. A custom event's codeName (preferred) or id from the
                    event definitions list — accepted either way, stored and
                    returned as the codeName. MUST be a custom event: built-in /
                    system (predefined) events are rejected (a tracker can only
                    fire custom events; create one a custom event definition you
                    created). A tracker is headless — no UI, no theme; it just
                    fires this event whenever its startRules trigger conditions
                    are met. null when unset.
                  nullable: true
              required:
                - event
              additionalProperties: {}
            - type: object
              properties:
                title:
                  description: >-
                    Title shown in the feed row and the detail view. Required to
                    publish — an untitled announcement would render a blank row.
                    Seeded from the content's `name` at create, then
                    INDEPENDENT: renaming the content later does not update the
                    title (and events/analytics label by the content name, not
                    this title). Plain string — NO `{{ }}` interpolation (braces
                    would render literally). For a personalized body use the
                    intro/detail content blocks.
                  type: string
                introContent:
                  description: >-
                    Rich content shown in the feed row (and in the popup, for
                    `distribution: "popup"`). Same block vocabulary as flow
                    steps MINUS questions: text / image / button / embed /
                    columns. Button actions here: start_content / navigate /
                    run_javascript only — no dismiss (feed items are marked
                    seen, not dismissed) and no goto_step.
                  type: array
                  items:
                    $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                enableReadMore:
                  description: >-
                    Adds a "Read more" button that opens a detail page rendered
                    from `detailContent`.
                  type: boolean
                readMoreLabel:
                  description: Label of the "Read more" button (default "Read more").
                  type: string
                detailContent:
                  description: >-
                    Full content of the "Read more" detail page — only rendered
                    when `enableReadMore` is true. Same block rules as
                    `introContent`.
                  type: array
                  items:
                    $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                distribution:
                  description: >-
                    How loudly users are notified: `silent` = appears in the
                    feed only; `badge` (default) = feed + unread-count badge on
                    the resource-center launcher; `popup` = feed + badge +
                    actively presented ONCE to each user (style per
                    `popupConfig`). Only the newest unseen popup self-presents;
                    it never re-shows after being seen.
                  type: string
                  enum:
                    - silent
                    - badge
                    - popup
                popupConfig:
                  description: >-
                    Popup presentation — only USED when `distribution` is
                    `popup` (stored and echoed under other distributions, taking
                    effect if distribution later switches to popup). Omit for
                    the default (bubble).
                  type: object
                  properties:
                    style:
                      type: string
                      enum:
                        - modal
                        - bubble
                      description: >-
                        `modal` = centered modal with overlay; `bubble` = speech
                        bubble anchored at the resource-center launcher.
                  required:
                    - style
              additionalProperties: {}
            - type: object
              properties:
                buttonText:
                  description: >-
                    Text on the floating resource-center launcher (only rendered
                    when the theme launcher is in text mode). Plain string — NO
                    `{{ }}` interpolation.
                  type: string
                headerText:
                  description: >-
                    Panel header title — but NOT on the default home view: with
                    a styled theme header (resourceCenter.headerBackground other
                    than "none", the hero look) the home view shows the logo +
                    background and this text does not render there. It renders
                    on the home view only under the compact "none" header style,
                    and on SUB-pages as the fallback title (when the tab/page
                    has no name). For a visible home greeting use a `richtext`
                    block. Plain string — NO `{{ }}` interpolation (braces would
                    render literally).
                  type: string
                tabs:
                  type: array
                  items:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                        description: >-
                          Tab label. Plain text — NO `{{ }}` interpolation
                          (braces would render literally).
                      icon:
                        type: object
                        properties:
                          source:
                            description: >-
                              Icon source. 'builtin' = a named icon from the
                              bundled RemixIcon set (see `type`); 'upload'/'url'
                              = a custom image via `url`; 'none' = no icon.
                            type: string
                            enum:
                              - none
                              - builtin
                              - upload
                              - url
                          type:
                            description: >-
                              Builtin icon name (when source='builtin'): a
                              RemixIcon name in kebab `-line`/`-fill` style —
                              e.g. `home-line`, `question-line`, `chat-line`,
                              `settings-line`, `rocket`. NOT lucide names:
                              `help-circle` / `sparkles` / `book-open` /
                              `message-circle` are not in the set — validate
                              warns on an unregistered name (the icon slot
                              renders empty; the block itself still shows).
                              Unsure of a name? Use source='none' rather than
                              guess. Common names + an intent→name table are in
                              the MCP authoring guide (icons section).
                            type: string
                          url:
                            type: string
                        additionalProperties: false
                      blocks:
                        default: []
                        description: >-
                          Tab blocks use the resource-center vocabulary —
                          richtext / divider / action / sub-page / content-list
                          / live-chat / announcement — NOT the flow content
                          blocks. Put text inside a `richtext` block: { "type":
                          "richtext", "content": [{ "object": "block", "type":
                          "text", "markdown": "…" }] }. A bare top-level text
                          block (type "text") is rejected here. At most one
                          `announcement` block per resource center (across all
                          tabs).
                        type: array
                        items:
                          oneOf:
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - richtext
                                name:
                                  type: string
                                content:
                                  default: []
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema0
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - divider
                                name:
                                  type: string
                              required:
                                - type
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - action
                                name:
                                  type: string
                                  description: >-
                                    Visible label of this block row. Supports
                                    `{{ attribute_code | default: "x" }}`
                                    user-attribute interpolation.
                                icon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                clickActions:
                                  default: []
                                  type: array
                                  items:
                                    oneOf:
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - goto_step
                                          step:
                                            type: string
                                            description: >-
                                              Target step: a step `key` declared
                                              elsewhere in the same write, or an
                                              existing step cvid. Resolved server-side
                                              to the cvid.
                                        required:
                                          - type
                                          - step
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - start_content
                                          content:
                                            type: string
                                            description: >-
                                              contentId of the flow or checklist to
                                              launch (an id from the content list) — a
                                              raw content id, NOT a step key (unlike
                                              goto_step). Must reference a flow or
                                              checklist (a banner / launcher /
                                              resource-center / tracker is rejected at
                                              write). The target must be PUBLISHED to
                                              actually start at runtime; an
                                              unknown/dangling id is rejected at
                                              validate.
                                          step:
                                            description: >-
                                              Optional cvid of a step within the
                                              launched flow to start at.
                                            type: string
                                        required:
                                          - type
                                          - content
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - navigate
                                          url:
                                            type: string
                                            description: >-
                                              Absolute URL, or an app-relative path
                                              ("/docs/x") resolved against the origin
                                              the user is on — relative paths are the
                                              normal choice for in-app navigation.
                                          newTab:
                                            description: >-
                                              Open the URL in a new browser tab
                                              instead of navigating the current one.
                                            type: boolean
                                        required:
                                          - type
                                          - url
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - dismiss
                                        required:
                                          - type
                                        description: >-
                                          Dismiss the piece the action lives on.
                                          NOT accepted everywhere this union
                                          appears: a resource center has no
                                          dismiss (closing the panel is a UI
                                          affordance, not an action) and an
                                          announcement is marked seen, never
                                          dismissed — writes there are rejected
                                          (E1017), not ignored. Flows / checklists
                                          / launchers / banners all accept it.
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - run_javascript
                                          script:
                                            type: string
                                        required:
                                          - type
                                          - script
                                        description: >-
                                          Read-back of an existing script action —
                                          scripts are not authorable through this
                                          API. Echo it back UNCHANGED (same
                                          script) when rewriting the surrounding
                                          list and the stored action is preserved;
                                          omitting it deletes it (action lists are
                                          full replacements). Authoring a new or
                                          edited script is rejected.
                                      - type: object
                                        properties:
                                          type:
                                            type: string
                                            enum:
                                              - unsupported
                                          note:
                                            type: string
                                        required:
                                          - type
                                        description: >-
                                          Echo-only placeholder for a stored
                                          action this schema cannot express
                                          (`note` = internal type). Echo it back
                                          to preserve the stored action; writing
                                          one fresh is rejected.
                              required:
                                - type
                                - name
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - sub-page
                                name:
                                  type: string
                                  description: >-
                                    Visible label of this block row. Supports
                                    `{{ attribute_code | default: "x" }}`
                                    user-attribute interpolation.
                                icon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                content:
                                  default: []
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema0
                              required:
                                - type
                                - name
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - content-list
                                name:
                                  type: string
                                  description: >-
                                    Visible label of this block row. Supports
                                    `{{ attribute_code | default: "x" }}`
                                    user-attribute interpolation.
                                icon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                flowIcon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                checklistIcon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                showSearchField:
                                  type: boolean
                                items:
                                  default: []
                                  type: array
                                  items:
                                    type: object
                                    properties:
                                      content:
                                        type: string
                                        description: >-
                                          Id of the flow/checklist this entry
                                          starts on click.
                                      contentType:
                                        type: string
                                        enum:
                                          - flow
                                          - checklist
                                      label:
                                        description: >-
                                          Display name for this list entry;
                                          omitted or empty falls back to the
                                          referenced content's admin name. `items`
                                          is a full-list replacement — when
                                          rewriting it, echo the read-back `label`
                                          or it is cleared.
                                        type: string
                                      icon:
                                        type: object
                                        properties:
                                          source:
                                            description: >-
                                              Icon source. 'inherit' (default) falls
                                              back to the block's
                                              flowIcon/checklistIcon; 'builtin' = a
                                              named RemixIcon (see `type`);
                                              'upload'/'url' = a custom image; 'none'
                                              = no icon.
                                            type: string
                                            enum:
                                              - none
                                              - builtin
                                              - upload
                                              - url
                                              - inherit
                                          type:
                                            description: >-
                                              Builtin icon name (when
                                              source='builtin'): a RemixIcon name in
                                              kebab `-line`/`-fill` style — e.g.
                                              `home-line`, `question-line`,
                                              `chat-line`, `settings-line`, `rocket`.
                                              NOT lucide names: `help-circle` /
                                              `sparkles` / `book-open` /
                                              `message-circle` are not in the set —
                                              validate warns on an unregistered name
                                              (the icon slot renders empty; the block
                                              itself still shows). Unsure of a name?
                                              Use source='none' rather than guess.
                                              Common names + an intent→name table are
                                              in the MCP authoring guide (icons
                                              section).
                                            type: string
                                          url:
                                            type: string
                                        additionalProperties: false
                                      navigateUrl:
                                        description: >-
                                          URL also opened when the entry is
                                          clicked, AFTER the referenced content
                                          starts — e.g. take the user to the page
                                          where the flow begins. Supports `{{
                                          attribute_code | default: "x" }}`
                                          interpolation.
                                        type: string
                                      navigateOpenType:
                                        description: >-
                                          Open `navigateUrl` in the same tab
                                          (default) or a new one.
                                        type: string
                                        enum:
                                          - same
                                          - new
                                      onlyShowWhen:
                                        type: array
                                        items:
                                          $ref: >-
                                            #/components/schemas/UpdateVersionBodyDto__schema1
                                    required:
                                      - content
                                      - contentType
                                    additionalProperties: false
                              required:
                                - type
                                - name
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - live-chat
                                name:
                                  type: string
                                  description: >-
                                    Visible label of this block row. Supports
                                    `{{ attribute_code | default: "x" }}`
                                    user-attribute interpolation.
                                icon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                                provider:
                                  type: string
                                  enum:
                                    - crisp
                                    - custom
                                    - freshchat
                                    - help-scout
                                    - hubspot
                                    - intercom
                                    - zendesk-classic
                                    - zendesk-messenger
                                  description: >-
                                    Which chat widget the click opens. The SDK
                                    only INVOKES the provider — the host page
                                    must already have that provider's script
                                    installed, or clicking opens nothing (the
                                    SDK logs a warning naming the provider, but
                                    its console output is off by default —
                                    visible only with the debug flag
                                    `localStorage.debug = 'usertour-widget:*'`).
                                    Not checkable at write time (the server
                                    cannot see the host page), so confirm which
                                    provider the host actually runs.
                                customCode:
                                  description: >-
                                    Only meaningful — and only RETURNED — when
                                    provider is 'custom': the script run on
                                    CLICK (not page load) via new Function;
                                    hosts can disable it with
                                    usertour.disableEvalJs(). Echo-only via the
                                    API — echo the stored code back unchanged
                                    (or omit the field) to keep it, empty string
                                    clears it; writing new or edited code is
                                    rejected (same security policy as
                                    run_javascript). Scripts can only be
                                    authored in the Usertour app. For other
                                    providers the field never appears in reads;
                                    any leftover script from a past provider
                                    switch stays stored and resurfaces if the
                                    provider returns to custom.
                                  type: string
                              required:
                                - type
                                - name
                                - provider
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - announcement
                                name:
                                  type: string
                                  description: >-
                                    Visible label of this block row. Supports
                                    `{{ attribute_code | default: "x" }}`
                                    user-attribute interpolation.
                                icon:
                                  type: object
                                  properties:
                                    source:
                                      description: >-
                                        Icon source. 'builtin' = a named icon
                                        from the bundled RemixIcon set (see
                                        `type`); 'upload'/'url' = a custom image
                                        via `url`; 'none' = no icon.
                                      type: string
                                      enum:
                                        - none
                                        - builtin
                                        - upload
                                        - url
                                    type:
                                      description: >-
                                        Builtin icon name (when
                                        source='builtin'): a RemixIcon name in
                                        kebab `-line`/`-fill` style — e.g.
                                        `home-line`, `question-line`,
                                        `chat-line`, `settings-line`, `rocket`.
                                        NOT lucide names: `help-circle` /
                                        `sparkles` / `book-open` /
                                        `message-circle` are not in the set —
                                        validate warns on an unregistered name
                                        (the icon slot renders empty; the block
                                        itself still shows). Unsure of a name?
                                        Use source='none' rather than guess.
                                        Common names + an intent→name table are
                                        in the MCP authoring guide (icons
                                        section).
                                      type: string
                                    url:
                                      type: string
                                  additionalProperties: false
                              required:
                                - type
                                - name
                              additionalProperties: false
                            - type: object
                              properties:
                                id:
                                  type: string
                                onlyShowWhen:
                                  type: array
                                  items:
                                    $ref: >-
                                      #/components/schemas/UpdateVersionBodyDto__schema1
                                type:
                                  type: string
                                  enum:
                                    - unsupported
                                note:
                                  type: string
                              required:
                                - type
                              additionalProperties: false
                    required:
                      - name
                    additionalProperties: false
              additionalProperties: {}
        scheduledAt:
          type: string
          description: >-
            Announcement versions only: the "announcement time" — the feed hides
            the announcement until this instant passes, and orders the feed by
            it (newest first). ISO date or datetime WITH timezone. `null` =
            clear (publish stamps the publish time instead). A future value
            defers visibility; the value carries across version forks.
          nullable: true
      additionalProperties: false
    ContentVersionDto:
      type: object
      properties:
        id:
          type: string
        object:
          type: string
          enum:
            - contentVersion
        number:
          type: number
        firstPublishedAt:
          type: string
          description: >-
            When this version FIRST went live (ISO). Non-null means the version
            is frozen: it can never be edited again — not even after
            unpublishing — edit by forking (by forking). null means it never
            went live — OR its first publish predates this stamp (older versions
            were never backfilled), so on old data null is not proof it never
            shipped. This is history, not live state: for "is it live NOW,
            where" read the content's `environments[]`; for who published what
            when, the publish history (available through the MCP).
          nullable: true
        themeId:
          type: string
          nullable: true
        questions:
          type: array
          items:
            type: object
            properties:
              object:
                type: string
                enum:
                  - question
              cvid:
                type: string
              name:
                type: string
              type:
                type: string
                enum:
                  - nps
                  - star-rating
                  - scale
                  - single-line-text
                  - multi-line-text
                  - multiple-choice
            required:
              - object
              - cvid
              - name
              - type
          nullable: true
        steps:
          type: array
          items:
            type: object
            properties:
              object:
                type: string
                enum:
                  - step
              id:
                type: string
              cvid:
                type: string
                description: >-
                  Stable step handle that SURVIVES forking (unlike `id`, which
                  is regenerated) — echo it on a write to update this step in
                  place. Prefer it over `id` for edits that must outlive a new
                  version.
                nullable: true
              name:
                type: string
              type:
                type: string
                enum:
                  - tooltip
                  - modal
                  - hidden
                  - bubble
              sequence:
                type: number
                description: >-
                  0-based display order. On write an explicit `sequence` wins;
                  steps without one fall back to their array index.
              themeId:
                type: string
                description: >-
                  Per-step theme override; null = this step inherits the flow
                  version's theme.
                nullable: true
              target:
                type: object
                properties:
                  selector:
                    type: string
                    minLength: 1
                    description: >-
                      A stable CSS selector for the element. The runtime targets
                      the FIRST match — so either make the selector unique, or
                      pair a stable non-unique selector with `nth` to pick the
                      intended match. A non-unique selector with no `nth`
                      targets the first (often wrong) element and the tooltip
                      silently won't render.
                  text:
                    description: >-
                      Optional refinement of `selector`. Requires the targeted
                      element's visible text to equal this (exact match, after
                      trim) — use it to pin a specific content/state (e.g. a
                      stable id whose displayed text you want to match: id +
                      text). It refines the element chosen by `selector`/`nth`;
                      on its own it does NOT search among multiple matches, so
                      disambiguate a non-unique selector with `nth`, not `text`
                      alone.
                    type: string
                  nth:
                    description: >-
                      Optional refinement of `selector`. 0-based index to pick
                      which match when the selector isn't unique — e.g. a stable
                      selector matching 3 elements + `nth: 1` targets the 2nd,
                      giving a unique result. Matches are taken in document
                      order (as they appear in the page HTML). Range 0–4 — only
                      the first 5 matches are addressable; a larger value is
                      rejected.
                    type: integer
                    minimum: 0
                    maximum: 4
                required:
                  - selector
              placement:
                anyOf:
                  - type: object
                    properties:
                      side:
                        description: >-
                          Which side of the target the tooltip sits on. OMIT
                          side+align to auto-position (the tooltip picks a spot
                          and flips to avoid the viewport edge — best when you
                          can't see the element). Setting side (or align) pins
                          that direction: the tooltip renders exactly there and
                          no longer auto-flips, so only pin when the element is
                          not near a screen edge. When READING a step back,
                          check `alignType` first: under `auto` the side/align
                          you see are just the auto starting position, not a
                          pin.
                        type: string
                        enum:
                          - top
                          - right
                          - bottom
                          - left
                      align:
                        description: Alignment along the side. See `side`.
                        type: string
                        enum:
                          - start
                          - center
                          - end
                      sideOffset:
                        description: >-
                          Pixels between the target and the tooltip, along
                          `side`.
                        type: number
                      alignOffset:
                        description: >-
                          Pixel shift along the alignment axis. Only applies
                          when `align` is `start` or `end` — at `center`
                          alignment the runtime ignores it silently.
                        type: number
                      alignType:
                        description: >-
                          Position mode. `auto` auto-positions and flips to
                          avoid the viewport edge (ignoring side/align); `fixed`
                          pins to side/align without flipping. Usually omit it:
                          providing side/align implies `fixed`, and omitting
                          them implies `auto`. Set it only to override that
                          (e.g. `auto` while still passing a side/align you want
                          ignored). Read-backs always carry concrete side/align
                          even in `auto` mode (the auto starting position,
                          bottom/center) — `alignType` is what governs, and
                          `auto` still flips at runtime.
                        type: string
                        enum:
                          - auto
                          - fixed
                      backdrop:
                        description: Dim the rest of the page while this tooltip is up.
                        type: boolean
                      blockTarget:
                        description: >-
                          Make the backdrop swallow clicks on the highlighted
                          element, so the user must use the tooltip. REQUIRES
                          `backdrop: true` — on its own it does nothing (the
                          renderer only consults it inside the backdrop branch).
                        type: boolean
                    additionalProperties: false
                  - type: object
                    properties:
                      position:
                        type: string
                        enum:
                          - leftTop
                          - centerTop
                          - rightTop
                          - leftCenter
                          - center
                          - rightCenter
                          - leftBottom
                          - centerBottom
                          - rightBottom
                      offsetX:
                        description: >-
                          Pixel shift from the grid cell. Applies in every cell
                          EXCEPT `position: "center"`, where both offsets are
                          ignored silently.
                        type: number
                      offsetY:
                        description: See `offsetX`.
                        type: number
                      backdrop:
                        type: boolean
                    required:
                      - position
                    additionalProperties: false
                description: >-
                  Two placement shapes, by step kind: a TOOLTIP (anchored to a
                  `target`) uses `{ side, align, sideOffset?, alignOffset?,
                  alignType? }` positioned relative to the element; a MODAL uses
                  `{ position, offsetX?, offsetY? }` on a 9-cell viewport grid
                  (e.g. `"center"`). Both may set `backdrop`; `blockTarget` is
                  TOOLTIP-ONLY (a modal already covers the page) and
                  additionally requires `backdrop: true` — it makes the backdrop
                  swallow clicks on the highlighted element. A BUBBLE step is
                  positioned by its THEME's bubble placement, so the only key it
                  accepts here is `{ backdrop }` (positional keys are rejected —
                  move the bubble by changing the theme); a HIDDEN step renders
                  no UI and rejects `placement` entirely.
              width:
                description: >-
                  Per-step width override in pixels (border-box outer width) —
                  absent = the theme's surface width.
                type: number
              skippable:
                type: boolean
              explicitCompletionStep:
                description: >-
                  Marks this step as the flow's completion point: reaching it
                  counts the flow as COMPLETED (progress hits 100 and the
                  completion event fires there), and later steps no longer
                  report progress. With no step marked, only reaching the LAST
                  step completes the flow — which is what a checklist task
                  waiting on "this flow completed" depends on.
                type: boolean
              content:
                type: array
                items:
                  $ref: '#/components/schemas/ContentVersionDto__schema0'
              triggers:
                type: array
                items:
                  type: object
                  properties:
                    when:
                      description: >-
                        REACTIVE slot — polled live in the browser while the
                        step is on screen, so it accepts only client-evaluable
                        condition types: attribute / current_url / element /
                        text_input / text_filled / time_window. Event / segment
                        / content_state conditions are server-evaluated and
                        rejected here (E1017). A trigger with NO `when` never
                        fires (an empty set is "not matched", not "always").
                      type: array
                      items:
                        $ref: '#/components/schemas/ContentVersionDto__schema1'
                    do:
                      type: array
                      items:
                        oneOf:
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - goto_step
                              step:
                                type: string
                                description: >-
                                  Target step: a step `key` declared elsewhere
                                  in the same write, or an existing step cvid.
                                  Resolved server-side to the cvid.
                            required:
                              - type
                              - step
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - start_content
                              content:
                                type: string
                                description: >-
                                  contentId of the flow or checklist to launch
                                  (an id from the content list) — a raw content
                                  id, NOT a step key (unlike goto_step). Must
                                  reference a flow or checklist (a banner /
                                  launcher / resource-center / tracker is
                                  rejected at write). The target must be
                                  PUBLISHED to actually start at runtime; an
                                  unknown/dangling id is rejected at validate.
                              step:
                                description: >-
                                  Optional cvid of a step within the launched
                                  flow to start at.
                                type: string
                            required:
                              - type
                              - content
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - navigate
                              url:
                                type: string
                                description: >-
                                  Absolute URL, or an app-relative path
                                  ("/docs/x") resolved against the origin the
                                  user is on — relative paths are the normal
                                  choice for in-app navigation.
                              newTab:
                                description: >-
                                  Open the URL in a new browser tab instead of
                                  navigating the current one.
                                type: boolean
                            required:
                              - type
                              - url
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - dismiss
                            required:
                              - type
                            description: >-
                              Dismiss the piece the action lives on. NOT
                              accepted everywhere this union appears: a resource
                              center has no dismiss (closing the panel is a UI
                              affordance, not an action) and an announcement is
                              marked seen, never dismissed — writes there are
                              rejected (E1017), not ignored. Flows / checklists
                              / launchers / banners all accept it.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - run_javascript
                              script:
                                type: string
                            required:
                              - type
                              - script
                            description: >-
                              Read-back of an existing script action — scripts
                              are not authorable through this API. Echo it back
                              UNCHANGED (same script) when rewriting the
                              surrounding list and the stored action is
                              preserved; omitting it deletes it (action lists
                              are full replacements). Authoring a new or edited
                              script is rejected.
                          - type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - unsupported
                              note:
                                type: string
                            required:
                              - type
                            description: >-
                              Echo-only placeholder for a stored action this
                              schema cannot express (`note` = internal type).
                              Echo it back to preserve the stored action;
                              writing one fresh is rejected.
                    waitSeconds:
                      description: >-
                        Delay in SECONDS between the `when` conditions matching
                        and the `do` actions firing. The timer arms the first
                        time `when` matches and the actions fire after the wait
                        EVEN IF the conditions have since stopped matching (the
                        match is latched, not re-checked). Capped at 300 seconds
                        by the runtime (a larger value is clamped).
                      type: number
                  required:
                    - do
              onClick:
                description: >-
                  Actions that run when the user clicks the step's TARGET
                  ELEMENT on the page (click-to-advance) — distinct from a
                  `button` block, whose actions fire on a button rendered inside
                  the step. `tooltip` steps only: the other kinds have no target
                  element to click, and the write rejects `onClick` on them.
                type: array
                items:
                  oneOf:
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - goto_step
                        step:
                          type: string
                          description: >-
                            Target step: a step `key` declared elsewhere in the
                            same write, or an existing step cvid. Resolved
                            server-side to the cvid.
                      required:
                        - type
                        - step
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - start_content
                        content:
                          type: string
                          description: >-
                            contentId of the flow or checklist to launch (an id
                            from the content list) — a raw content id, NOT a
                            step key (unlike goto_step). Must reference a flow
                            or checklist (a banner / launcher / resource-center
                            / tracker is rejected at write). The target must be
                            PUBLISHED to actually start at runtime; an
                            unknown/dangling id is rejected at validate.
                        step:
                          description: >-
                            Optional cvid of a step within the launched flow to
                            start at.
                          type: string
                      required:
                        - type
                        - content
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - navigate
                        url:
                          type: string
                          description: >-
                            Absolute URL, or an app-relative path ("/docs/x")
                            resolved against the origin the user is on —
                            relative paths are the normal choice for in-app
                            navigation.
                        newTab:
                          description: >-
                            Open the URL in a new browser tab instead of
                            navigating the current one.
                          type: boolean
                      required:
                        - type
                        - url
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - dismiss
                      required:
                        - type
                      description: >-
                        Dismiss the piece the action lives on. NOT accepted
                        everywhere this union appears: a resource center has no
                        dismiss (closing the panel is a UI affordance, not an
                        action) and an announcement is marked seen, never
                        dismissed — writes there are rejected (E1017), not
                        ignored. Flows / checklists / launchers / banners all
                        accept it.
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - run_javascript
                        script:
                          type: string
                      required:
                        - type
                        - script
                      description: >-
                        Read-back of an existing script action — scripts are not
                        authorable through this API. Echo it back UNCHANGED
                        (same script) when rewriting the surrounding list and
                        the stored action is preserved; omitting it deletes it
                        (action lists are full replacements). Authoring a new or
                        edited script is rejected.
                    - type: object
                      properties:
                        type:
                          type: string
                          enum:
                            - unsupported
                        note:
                          type: string
                      required:
                        - type
                      description: >-
                        Echo-only placeholder for a stored action this schema
                        cannot express (`note` = internal type). Echo it back to
                        preserve the stored action; writing one fresh is
                        rejected.
              advanced:
                type: object
                properties:
                  hasUnsupported:
                    type: boolean
                    description: >-
                      true = this step carries stored configuration this API
                      cannot express (e.g. an auto-recorded element
                      fingerprint). Read-only signal: echoing the step back
                      preserves that configuration untouched; it is not editable
                      here.
                required:
                  - hasUnsupported
            required:
              - object
              - id
              - cvid
              - name
              - type
              - sequence
              - themeId
              - content
        startRules:
          type: object
          properties:
            when:
              description: >-
                Start conditions (full replacement when present). Omit to keep
                the existing conditions and change only the settings.
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema1'
            frequency:
              description: >-
                How often the content may auto-start (flow/checklist only). Left
                unset on a write, the builder default (`once`) is seeded and
                STORED — read-backs show the effective mode explicitly. A
                version stored with NO frequency at all (reachable only through
                legacy/builder-external writes, never through this API) runs
                with NO limit: it starts again every time its rules match once
                the prior session ends — validate_content_version warns on that
                state.
              type: object
              properties:
                mode:
                  type: string
                  enum:
                    - once
                    - multiple
                    - unlimited
                  description: >-
                    once = show a single time; multiple = up to N times per
                    window; unlimited = every time the conditions match (subject
                    to `every`).
                every:
                  description: >-
                    Re-show window. Used by `multiple` (with `times`) and
                    `unlimited`; ignored for `once`. If omitted for those modes
                    a default window is applied. Manual and programmatic starts
                    also count toward the `multiple` limit.
                  type: object
                  properties:
                    times:
                      type: number
                    duration:
                      type: number
                    unit:
                      type: string
                      enum:
                        - seconds
                        - minutes
                        - hours
                        - days
                  required:
                    - duration
                    - unit
                atLeast:
                  description: >-
                    Only auto-start if no OTHER content of the SAME type has
                    been shown within this window — and since only flows accept
                    this knob, in practice: no other FLOW. A banner / checklist
                    / launcher showing does NOT block it. Avoids stacking
                    several flows on a user at once.
                  type: object
                  properties:
                    duration:
                      type: number
                    unit:
                      type: string
                      enum:
                        - seconds
                        - minutes
                        - hours
                        - days
                  required:
                    - duration
                    - unit
              required:
                - mode
            priority:
              description: >-
                Tie-breaker when a user matches the start conditions for more
                than one piece of content at the same time — the higher priority
                starts first. Content with no priority set ranks as `medium`.
              type: string
              enum:
                - highest
                - high
                - medium
                - low
                - lowest
            waitSeconds:
              description: >-
                Delay in SECONDS between the start conditions matching and the
                content becoming ELIGIBLE to start. The countdown itself
                survives the conditions un-matching mid-wait, but unlike a
                trigger wait (which fires its actions regardless), an elapsed
                start-rule wait guarantees nothing: the conditions are
                RE-CHECKED at show time, and the content starts at the next
                moment they match again. One exception: when a session of the
                same content type starts or ends mid-wait, in-flight timers are
                cancelled and re-armed — a still-matching version then restarts
                its wait from zero. Capped at 300 seconds by the runtime (a
                larger value is clamped).
              type: number
            startIfNotComplete:
              description: >-
                When true, this content won't auto-start for users who have
                already completed it.
              type: boolean
        hideRules:
          type: object
          properties:
            when:
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema1'
          description: >-
            While `when` matches, on-screen content of this version is hidden —
            the session is SUSPENDED, not ended: when the conditions stop
            matching the same session reappears at the same step. Use start-rule
            conditions to keep content from starting; use hide rules to blank it
            in specific places (e.g. a settings page).
        data:
          description: >-
            Decompiled type-specific body for non-flow content — the same six
            per-type shapes as the write `data` (that schema is the field
            dictionary), fully populated on read. Present only when the `data`
            expand is requested; a flow has no `data` — its body is `steps`.
        scheduledAt:
          description: >-
            Announcement versions only: the "announcement time" gating feed
            visibility and ordering. Absent on other content types and until set
            (publish stamps it when the author left it null, so published
            announcements always carry one).
          type: string
        updatedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
      required:
        - id
        - object
        - number
        - firstPublishedAt
        - themeId
        - questions
        - updatedAt
        - createdAt
    ErrorResponseDto:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: >-
                Stable machine-readable code (e.g. E1017). Match on this, never
                on `message`.
            message:
              type: string
              description: Human-readable summary. Wording may change between releases.
            issues:
              description: >-
                Validation errors (E1017) may carry one entry per problem so
                every field can be fixed in a single round-trip. Absent on other
                errors.
              type: array
              items:
                type: object
                properties:
                  rule:
                    type: string
                    description: >-
                      Which validation layer rejected it: schema |
                      reactive_condition | action_not_allowed | step_shape |
                      reference_target | auto_start | media_url. New values may
                      be added; treat an unknown value as a generic validation
                      failure.
                  message:
                    type: string
                  path:
                    description: >-
                      Path into the request body (e.g.
                      `steps[0].triggers[0].when[1]`).
                    type: string
                required:
                  - rule
                  - message
            doc_url:
              type: string
              description: Base URL of the API documentation.
      required:
        - error
    UpdateVersionBodyDto__schema0:
      oneOf:
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - text
            markdown:
              type: string
              description: >-
                A small markdown subset: paragraphs, `# `/`## ` headings (h1/h2
                only — no h3+), `-`/`*` and `1.` lists, ``` code fences; inline
                `**bold**`, `*italic*`, `[text](url)`, and `{{ attribute_code |
                default: "x" }}` for user attributes. Anything outside this
                subset is SILENTLY normalized, not rejected: h3+ → h2;
                blockquotes flatten to paragraphs; tables, horizontal rules,
                strikethrough, inline images/code, and liquid filters other than
                `default` are dropped. Unsupported syntax won't round-trip —
                don't rely on it.
          required:
            - type
            - markdown
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - image
            url:
              type: string
              minLength: 1
            alt:
              type: string
            link:
              type: object
              properties:
                url:
                  type: string
                newTab:
                  type: boolean
              required:
                - url
            width:
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - url
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - button
            text:
              type: string
            actions:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - goto_step
                      step:
                        type: string
                        description: >-
                          Target step: a step `key` declared elsewhere in the
                          same write, or an existing step cvid. Resolved
                          server-side to the cvid.
                    required:
                      - type
                      - step
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - start_content
                      content:
                        type: string
                        description: >-
                          contentId of the flow or checklist to launch (an id
                          from the content list) — a raw content id, NOT a step
                          key (unlike goto_step). Must reference a flow or
                          checklist (a banner / launcher / resource-center /
                          tracker is rejected at write). The target must be
                          PUBLISHED to actually start at runtime; an
                          unknown/dangling id is rejected at validate.
                      step:
                        description: >-
                          Optional cvid of a step within the launched flow to
                          start at.
                        type: string
                    required:
                      - type
                      - content
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - navigate
                      url:
                        type: string
                        description: >-
                          Absolute URL, or an app-relative path ("/docs/x")
                          resolved against the origin the user is on — relative
                          paths are the normal choice for in-app navigation.
                      newTab:
                        description: >-
                          Open the URL in a new browser tab instead of
                          navigating the current one.
                        type: boolean
                    required:
                      - type
                      - url
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - dismiss
                    required:
                      - type
                    description: >-
                      Dismiss the piece the action lives on. NOT accepted
                      everywhere this union appears: a resource center has no
                      dismiss (closing the panel is a UI affordance, not an
                      action) and an announcement is marked seen, never
                      dismissed — writes there are rejected (E1017), not
                      ignored. Flows / checklists / launchers / banners all
                      accept it.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - run_javascript
                      script:
                        type: string
                    required:
                      - type
                      - script
                    description: >-
                      Read-back of an existing script action — scripts are not
                      authorable through this API. Echo it back UNCHANGED (same
                      script) when rewriting the surrounding list and the stored
                      action is preserved; omitting it deletes it (action lists
                      are full replacements). Authoring a new or edited script
                      is rejected.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - unsupported
                      note:
                        type: string
                    required:
                      - type
                    description: >-
                      Echo-only placeholder for a stored action this schema
                      cannot express (`note` = internal type). Echo it back to
                      preserve the stored action; writing one fresh is rejected.
            disabledWhen:
              description: >-
                REACTIVE slot — polled live in the browser (the button disables
                the moment the conditions match). Client-evaluable condition
                types only: attribute / current_url / element / text_input /
                text_filled / time_window; event / segment / content_state are
                rejected (E1017).
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
            hiddenWhen:
              description: >-
                REACTIVE slot — polled live in the browser (the button
                shows/hides as conditions change). Same client-evaluable-only
                rule as `disabledWhen`.
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
            variant:
              type: string
              enum:
                - primary
                - secondary
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - text
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - embed
            url:
              type: string
              minLength: 1
              description: >-
                Paste the page's normal URL (e.g. a youtube.com/watch link) — on
                write it is resolved through the standard oEmbed provider
                registry (YouTube, Vimeo, Loom, Figma, …) and the provider's
                official embed markup is stored, so you never hand-build /embed/
                URLs. A URL no provider claims is iframed as-is — it renders
                only if that site allows being framed (no X-Frame-Options/CSP
                block).
            width:
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            height:
              description: >-
                Embed height. Optional ONLY for provider embeds (YouTube/Vimeo/…
                size themselves by aspect ratio); a URL with NO oEmbed provider
                has no ratio, and omitting a pixel height leaves the iframe at
                the browser's built-in default — a strip ~150px tall, almost
                never the intended size (validate warns). For plain-iframe URLs
                always set `{ "unit": "pixels", "value": … }`.
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - url
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - question
            question:
              oneOf:
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - nps
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    lowLabel:
                      type: string
                    highLabel:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - rating
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    style:
                      type: string
                      enum:
                        - star
                        - scale
                      description: >-
                        star = star rating; scale = a numeric scale. A "scale"
                        question IS a rating with style:"scale" — there is no
                        separate "scale" kind.
                    range:
                      type: object
                      properties:
                        low:
                          type: number
                        high:
                          type: number
                      required:
                        - low
                        - high
                      description: 'Numeric range, e.g. { low: 1, high: 5 }.'
                    lowLabel:
                      type: string
                    highLabel:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - style
                    - range
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - text
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    multiline:
                      type: boolean
                    placeholder:
                      type: string
                    buttonText:
                      type: string
                    required:
                      description: >-
                        Require an answer before submit. ONLY `text` supports
                        this — nps / rating / choice cannot be marked required.
                      type: boolean
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - multiline
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - choice
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    options:
                      type: array
                      items:
                        type: object
                        properties:
                          label:
                            type: string
                          value:
                            type: string
                        required:
                          - label
                          - value
                      description: >-
                        Each option has a human-facing `label` and a stored
                        `value` — the `value` is what gets recorded/bound as the
                        answer.
                    allowMultiple:
                      type: boolean
                      description: >-
                        false = single-select, true = multi-select. A
                        multi-select answer needs a `list`-typed bound
                        attribute.
                    enableOther:
                      type: boolean
                    otherPlaceholder:
                      type: string
                    shuffle:
                      type: boolean
                    buttonText:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - options
                    - allowMultiple
            actions:
              description: >-
                Actions that fire when this question is answered (on pick for
                nps/rating/single-select; on its Submit button for
                text/multi-select). Put a `goto_step` HERE to advance to the
                next step — without it the question records the answer but the
                flow does NOT advance (validate flags the next step "not
                reachable"). Do NOT add a separate `button` block just to
                advance: it doubles up with the question's own submit
                affordance.
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - goto_step
                      step:
                        type: string
                        description: >-
                          Target step: a step `key` declared elsewhere in the
                          same write, or an existing step cvid. Resolved
                          server-side to the cvid.
                    required:
                      - type
                      - step
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - start_content
                      content:
                        type: string
                        description: >-
                          contentId of the flow or checklist to launch (an id
                          from the content list) — a raw content id, NOT a step
                          key (unlike goto_step). Must reference a flow or
                          checklist (a banner / launcher / resource-center /
                          tracker is rejected at write). The target must be
                          PUBLISHED to actually start at runtime; an
                          unknown/dangling id is rejected at validate.
                      step:
                        description: >-
                          Optional cvid of a step within the launched flow to
                          start at.
                        type: string
                    required:
                      - type
                      - content
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - navigate
                      url:
                        type: string
                        description: >-
                          Absolute URL, or an app-relative path ("/docs/x")
                          resolved against the origin the user is on — relative
                          paths are the normal choice for in-app navigation.
                      newTab:
                        description: >-
                          Open the URL in a new browser tab instead of
                          navigating the current one.
                        type: boolean
                    required:
                      - type
                      - url
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - dismiss
                    required:
                      - type
                    description: >-
                      Dismiss the piece the action lives on. NOT accepted
                      everywhere this union appears: a resource center has no
                      dismiss (closing the panel is a UI affordance, not an
                      action) and an announcement is marked seen, never
                      dismissed — writes there are rejected (E1017), not
                      ignored. Flows / checklists / launchers / banners all
                      accept it.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - run_javascript
                      script:
                        type: string
                    required:
                      - type
                      - script
                    description: >-
                      Read-back of an existing script action — scripts are not
                      authorable through this API. Echo it back UNCHANGED (same
                      script) when rewriting the surrounding list and the stored
                      action is preserved; omitting it deletes it (action lists
                      are full replacements). Authoring a new or edited script
                      is rejected.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - unsupported
                      note:
                        type: string
                    required:
                      - type
                    description: >-
                      Echo-only placeholder for a stored action this schema
                      cannot express (`note` = internal type). Echo it back to
                      preserve the stored action; writing one fresh is rejected.
          required:
            - type
            - question
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - columns
            columns:
              type: array
              items:
                type: object
                properties:
                  width:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum:
                          - percent
                          - pixels
                          - fill
                      value:
                        type: number
                        minimum: 0
                    required:
                      - unit
                  justify:
                    description: >-
                      Horizontal alignment of this column's own block(s) within
                      the column's width — use "end"/"center" to right-align or
                      center a lone button (a single-column `columns` block).
                    type: string
                    enum:
                      - start
                      - center
                      - end
                      - between
                      - around
                      - evenly
                  align:
                    type: string
                    enum:
                      - start
                      - center
                      - end
                      - baseline
                  padding:
                    type: object
                    properties:
                      enabled:
                        type: boolean
                      top:
                        type: number
                      bottom:
                        type: number
                      left:
                        type: number
                      right:
                        type: number
                  blocks:
                    type: array
                    items:
                      $ref: '#/components/schemas/UpdateVersionBodyDto__schema0'
                required:
                  - blocks
              description: >-
                One entry per column, laid out left-to-right. Each column is a
                mini vertical stack of `blocks` (usually one).
          required:
            - type
            - columns
          description: >-
            Lays 2+ blocks out side by side in one row. Top-level `content`
            blocks otherwise stack vertically — each is its own full-width row —
            so two `button` blocks placed directly in `content` render as two
            stacked rows, NOT a button pair. For a modal/tooltip footer with a
            Skip + primary button: one `columns` block with two `{ width: {
            unit: "fill" }, blocks: [...] }` entries, one button per column.
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - unsupported
            note:
              type: string
          required:
            - type
    UpdateVersionBodyDto__schema1:
      oneOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - group
            match:
              type: string
              enum:
                - all
                - any
            conditions:
              minItems: 1
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
              description: >-
                The grouped conditions — at least one. An EMPTY group is not "no
                filter": it never matches, so next to an AND it makes the whole
                rule unmatchable, and writing one is rejected. A version saved
                with an empty group in the BUILDER still reads back with it
                (validate warns); writing that list back is refused until the
                group is filled or dropped.
          required:
            - type
            - match
            - conditions
        - type: object
          properties:
            type:
              type: string
              enum:
                - attribute
            scope:
              type: string
              enum:
                - user
                - company
                - companyMembership
              description: >-
                Which entity owns the attribute — `user` (the end user),
                `company`, or `companyMembership`. Same value as the attribute
                definition's `scope` (see the attribute definitions list);
                required to disambiguate a codeName that exists in more than one
                scope.
            attribute:
              type: string
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - any
                - empty
                - lt
                - lte
                - gt
                - gte
                - between
                - 'true'
                - 'false'
                - includes_any
                - includes_all
                - not_includes_any
                - not_includes_all
                - less_than
                - exactly
                - more_than
                - before
                - 'on'
                - after
              description: >-
                Operator — the allowed set depends on the attribute dataType.
                String: is | not | contains | not_contains | starts_with |
                ends_with | any | empty. Number: is | not | lt | lte | gt | gte
                | between | any | empty. Boolean: true | false | any | empty.
                List: includes_any | includes_all | not_includes_any |
                not_includes_all | any | empty. DateTime: less_than | exactly |
                more_than (relative — `value` is a number of days) | before | on
                | after (`value` is an absolute date) | any | empty. The
                relative ops are ONE-SIDED bounds around (now − N days):
                `less_than N` = the date is AFTER now−N — so it also matches
                every FUTURE date, and on a future-dated attribute (a trial end,
                a renewal date) it is NOT "within the last N days"; `more_than
                N` = the date is BEFORE now−N. **"Signed up in the last N days"
                therefore needs BOTH bounds** — `less_than N` AND `more_than 0`
                in one `all` group; `less_than N` alone silently includes anyone
                whose date is in the future (a mis-mapped trial-end column, a
                clock/timezone slip), and those are exactly the users a new-user
                audience must not contain (observed in testing). Negative N
                shifts the bound into the future: the rolling "within the NEXT 7
                days" window is `less_than` value "0" AND `more_than` value "-7"
                (two conditions, both required). The relative ops are
                DAY-granularity only — no unit field; for hour/minute windows
                use an `event` condition with a `within` (which has a `unit`).
            value:
              description: >-
                The comparison value (string / number-as-string / date). Omit
                for any/empty/true/false.
              type: string
            value2:
              description: >-
                Upper bound for the `between` operator (`value` is the lower
                bound).
              type: string
            values:
              description: Values for the List operators (includes_any / includes_all / …).
              type: array
              items:
                type: string
          required:
            - type
            - scope
            - attribute
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - segment
            segment:
              type: string
            in:
              type: boolean
          required:
            - type
            - segment
            - in
        - type: object
          properties:
            type:
              type: string
              enum:
                - current_url
            includes:
              type: array
              items:
                type: string
              description: >-
                URL patterns (anchored whole-url match, NOT substring/regex).
                `*` = wildcard within one url part; `:name` = one path segment.
                A bare `*` (i.e. `["*"]`) matches EVERY page on every host incl.
                deep paths — the canonical always-on / whole-site pattern (use
                it when content should be available everywhere). Scope it down
                instead with: `*/` (homepage only — path exactly `/`),
                `*/pricing` (one page), `*/app/*` (a section + below),
                `host.com/*` (any page on a specific host). Multiple patterns
                are OR-matched: the URL matches this list if it matches ANY one
                pattern (so "/tasks OR /dashboard" is one condition with both
                patterns here — no group needed).
            excludes:
              description: >-
                URL patterns to exclude (same syntax as includes); excludes win
                over includes.
              type: array
              items:
                type: string
          required:
            - type
            - includes
        - type: object
          properties:
            type:
              type: string
              enum:
                - element
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
            state:
              type: string
              enum:
                - present
                - hidden
                - disabled
                - enabled
                - clicked
                - unclicked
              description: >-
                `present` means NOT CLIPPED AWAY: the element is in the DOM and
                its box lies inside the viewport / its scroll ancestors —
                scrolled off-screen or `display:none` never satisfies it (and
                `hidden` is its negation). It is NOT "the user can see something
                there": an EMPTY, zero-height placeholder node satisfies
                `present` (observed in testing: a checklist task keyed on an
                initially-empty `<p>` status line ticked itself the moment the
                checklist appeared, before the shopper did anything). So do not
                use element presence as a proxy for "the app has said
                something": most apps keep the container mounted and only fill
                in its text. Match the TEXT instead (`target.text` + `present`,
                or the negation trick: the old text `hidden`). Appearances
                shorter than about a second can be missed entirely.
                `disabled`/`enabled` read the element disabled state at
                evaluation time. **`clicked` means "clicked since page load AND
                the element is STILL in the DOM right now"** — both halves,
                re-checked every evaluation. The click memory latches (the
                listener attaches the FIRST time the condition is evaluated, so
                earlier clicks are invisible, and the memory survives a
                re-render), but the element lookup is redone each poll. Two
                consequences, one of them silent: (1) **an element that UNMOUNTS
                on click can NEVER satisfy it** — the click lands, the element
                vanishes, the lookup fails from then on and the condition stays
                false forever with no error (observed in testing: a tracker on a
                button that clears its own toolbar counted ZERO real clicks);
                (2) an element that unmounts and REMOUNTS satisfies it again, so
                a tracker gated on it fires once per remount — not once per page
                load. Unlike `present`, this lookup does NOT require viewport
                visibility: scrolling the target off-screen keeps `clicked`
                true. `unclicked` negates the same pair, so it is also false
                while the element is absent. To count a COMPLETED action,
                condition on what the app shows afterwards (a success toast, a
                state change) rather than `clicked` on the button that starts
                it.
          required:
            - type
            - state
        - type: object
          properties:
            type:
              type: string
              enum:
                - content_state
            content:
              type: string
              description: >-
                contentId of the FLOW or CHECKLIST whose per-user state to check
                (an id from the content list). Only flows and checklists record
                this state — referencing a banner / launcher / resource-center /
                tracker is rejected at write.
            state:
              type: string
              enum:
                - seen
                - unseen
                - completed
                - uncompleted
                - active
                - inactive
              description: >-
                The referenced flow/checklist's state for THIS user. seen =
                started at least once (for a flow, TRUE from the moment it
                opens; for a checklist, TRUE only once the user EXPANDS the
                panel — a `initialDisplay: "button"` checklist whose launcher is
                never clicked stays unseen forever); unseen = never started;
                active = currently open/running; inactive = NOT currently
                running (covers both never-started and ran-then-closed);
                completed = reached a goal/completion step; uncompleted = not
                completed. To gate piece B until flow A has run AND closed (the
                usual "show next thing after the welcome flow" sequencing), use
                `seen` AND `inactive` together — `seen` alone fires while A is
                still open (B piles on top), and `completed` alone strands users
                who skip/dismiss A.
          required:
            - type
            - content
            - state
        - type: object
          properties:
            type:
              type: string
              enum:
                - event
            event:
              type: string
            count:
              description: >-
                How many times the event must have occurred. Omit it for the
                common case "the event has happened" (treated as at_least 1).
                Set `op`/`n` for a threshold (`between` needs `n` and `n2`).
                `at_least`/`between` require n ≥ 1; use `at_most`/`exactly` with
                0 for "never happened".
              type: object
              properties:
                op:
                  type: string
                  enum:
                    - at_least
                    - at_most
                    - exactly
                    - between
                'n':
                  type: integer
                  minimum: 0
                  maximum: 9007199254740991
                n2:
                  type: integer
                  minimum: 0
                  maximum: 9007199254740991
              required:
                - op
                - 'n'
            within:
              description: >-
                Optional time window for the event count. Omit it (or use
                `any_time`) to count over all time — "the event has ever
                happened". Any other `op` (`in_the_last` / `more_than` /
                `between`) requires BOTH `value` and `unit`, and `between` also
                `value2` — rejected at write otherwise.
              type: object
              properties:
                op:
                  type: string
                  enum:
                    - in_the_last
                    - more_than
                    - between
                    - any_time
                value:
                  type: number
                value2:
                  type: number
                unit:
                  type: string
                  enum:
                    - seconds
                    - minutes
                    - hours
                    - days
              required:
                - op
            scope:
              description: >-
                Whose event activity to count (default `current_user`).
                `current_user` = only this user's own events.
                `current_user_in_company` = this user's events, but counted
                within their currently-associated company context (needs the
                user associated to a company via `group()` / the
                company-membership API). `any_user_in_company` = events by ANY
                user in this user's company — account-level activity (e.g.
                "anyone on the account has done X"). The two company scopes
                require the user to be in a company or they never match.
              type: string
              enum:
                - current_user
                - current_user_in_company
                - any_user_in_company
            where:
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema2'
          required:
            - type
            - event
        - type: object
          properties:
            type:
              type: string
              enum:
                - text_input
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - match
                - unmatch
                - any
                - empty
            value:
              type: string
          required:
            - type
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - text_filled
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
          required:
            - type
        - type: object
          properties:
            type:
              type: string
              enum:
                - time_window
            start:
              type: string
              description: >-
                Window start (ISO datetime). REQUIRED — the runtime never
                matches a window without a start, so an end-only window is
                rejected at write. For "until X" semantics, set start to any
                past instant and end to X.
            end:
              description: >-
                Window end (ISO datetime). Omit for an open-ended "from start
                onwards" window.
              type: string
          required:
            - type
            - start
        - type: object
          properties:
            type:
              type: string
              enum:
                - unsupported
            note:
              type: string
          required:
            - type
          description: >-
            Read-side placeholder for a stored condition this API cannot express
            (`note` says what it stands for — usually a DEAD condition the
            runtime never matches: a deleted attribute/event, an end-only time
            window). It cannot be written back (the placeholder carries no data
            to preserve): echoing it is rejected. Either remove it from the list
            you write — an explicit choice that DELETES the stored condition;
            mind that a never-matching node inside an AND list pins the whole
            rule to "never fires", so deleting it can bring the remaining
            conditions to life — or repair the original condition in the
            Usertour builder first.
    UpdateVersionBodyDto__schema3:
      anyOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - task_clicked
          required:
            - type
        - type: object
          properties:
            type:
              type: string
              enum:
                - group
            match:
              type: string
              enum:
                - all
                - any
            conditions:
              minItems: 1
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema3'
              description: >-
                The grouped conditions — at least one. An EMPTY group is not "no
                filter": it never matches, so next to an AND it makes the whole
                rule unmatchable, and writing one is rejected. A version saved
                with an empty group in the BUILDER still reads back with it
                (validate warns); writing that list back is refused until the
                group is filled or dropped.
          required:
            - type
            - match
            - conditions
        - $ref: '#/components/schemas/UpdateVersionBodyDto__schema1'
    ContentVersionDto__schema0:
      oneOf:
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - text
            markdown:
              type: string
              description: >-
                A small markdown subset: paragraphs, `# `/`## ` headings (h1/h2
                only — no h3+), `-`/`*` and `1.` lists, ``` code fences; inline
                `**bold**`, `*italic*`, `[text](url)`, and `{{ attribute_code |
                default: "x" }}` for user attributes. Anything outside this
                subset is SILENTLY normalized, not rejected: h3+ → h2;
                blockquotes flatten to paragraphs; tables, horizontal rules,
                strikethrough, inline images/code, and liquid filters other than
                `default` are dropped. Unsupported syntax won't round-trip —
                don't rely on it.
          required:
            - type
            - markdown
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - image
            url:
              type: string
              minLength: 1
            alt:
              type: string
            link:
              type: object
              properties:
                url:
                  type: string
                newTab:
                  type: boolean
              required:
                - url
            width:
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - url
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - button
            text:
              type: string
            actions:
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - goto_step
                      step:
                        type: string
                        description: >-
                          Target step: a step `key` declared elsewhere in the
                          same write, or an existing step cvid. Resolved
                          server-side to the cvid.
                    required:
                      - type
                      - step
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - start_content
                      content:
                        type: string
                        description: >-
                          contentId of the flow or checklist to launch (an id
                          from the content list) — a raw content id, NOT a step
                          key (unlike goto_step). Must reference a flow or
                          checklist (a banner / launcher / resource-center /
                          tracker is rejected at write). The target must be
                          PUBLISHED to actually start at runtime; an
                          unknown/dangling id is rejected at validate.
                      step:
                        description: >-
                          Optional cvid of a step within the launched flow to
                          start at.
                        type: string
                    required:
                      - type
                      - content
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - navigate
                      url:
                        type: string
                        description: >-
                          Absolute URL, or an app-relative path ("/docs/x")
                          resolved against the origin the user is on — relative
                          paths are the normal choice for in-app navigation.
                      newTab:
                        description: >-
                          Open the URL in a new browser tab instead of
                          navigating the current one.
                        type: boolean
                    required:
                      - type
                      - url
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - dismiss
                    required:
                      - type
                    description: >-
                      Dismiss the piece the action lives on. NOT accepted
                      everywhere this union appears: a resource center has no
                      dismiss (closing the panel is a UI affordance, not an
                      action) and an announcement is marked seen, never
                      dismissed — writes there are rejected (E1017), not
                      ignored. Flows / checklists / launchers / banners all
                      accept it.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - run_javascript
                      script:
                        type: string
                    required:
                      - type
                      - script
                    description: >-
                      Read-back of an existing script action — scripts are not
                      authorable through this API. Echo it back UNCHANGED (same
                      script) when rewriting the surrounding list and the stored
                      action is preserved; omitting it deletes it (action lists
                      are full replacements). Authoring a new or edited script
                      is rejected.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - unsupported
                      note:
                        type: string
                    required:
                      - type
                    description: >-
                      Echo-only placeholder for a stored action this schema
                      cannot express (`note` = internal type). Echo it back to
                      preserve the stored action; writing one fresh is rejected.
            disabledWhen:
              description: >-
                REACTIVE slot — polled live in the browser (the button disables
                the moment the conditions match). Client-evaluable condition
                types only: attribute / current_url / element / text_input /
                text_filled / time_window; event / segment / content_state are
                rejected (E1017).
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema1'
            hiddenWhen:
              description: >-
                REACTIVE slot — polled live in the browser (the button
                shows/hides as conditions change). Same client-evaluable-only
                rule as `disabledWhen`.
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema1'
            variant:
              type: string
              enum:
                - primary
                - secondary
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - text
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - embed
            url:
              type: string
              minLength: 1
              description: >-
                Paste the page's normal URL (e.g. a youtube.com/watch link) — on
                write it is resolved through the standard oEmbed provider
                registry (YouTube, Vimeo, Loom, Figma, …) and the provider's
                official embed markup is stored, so you never hand-build /embed/
                URLs. A URL no provider claims is iframed as-is — it renders
                only if that site allows being framed (no X-Frame-Options/CSP
                block).
            width:
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            height:
              description: >-
                Embed height. Optional ONLY for provider embeds (YouTube/Vimeo/…
                size themselves by aspect ratio); a URL with NO oEmbed provider
                has no ratio, and omitting a pixel height leaves the iframe at
                the browser's built-in default — a strip ~150px tall, almost
                never the intended size (validate warns). For plain-iframe URLs
                always set `{ "unit": "pixels", "value": … }`.
              type: object
              properties:
                unit:
                  type: string
                  enum:
                    - percent
                    - pixels
                value:
                  type: number
                  minimum: 0
              required:
                - unit
            margin:
              type: object
              properties:
                enabled:
                  type: boolean
                top:
                  type: number
                bottom:
                  type: number
                left:
                  type: number
                right:
                  type: number
          required:
            - type
            - url
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - question
            question:
              oneOf:
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - nps
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    lowLabel:
                      type: string
                    highLabel:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - rating
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    style:
                      type: string
                      enum:
                        - star
                        - scale
                      description: >-
                        star = star rating; scale = a numeric scale. A "scale"
                        question IS a rating with style:"scale" — there is no
                        separate "scale" kind.
                    range:
                      type: object
                      properties:
                        low:
                          type: number
                        high:
                          type: number
                      required:
                        - low
                        - high
                      description: 'Numeric range, e.g. { low: 1, high: 5 }.'
                    lowLabel:
                      type: string
                    highLabel:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - style
                    - range
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - text
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    multiline:
                      type: boolean
                    placeholder:
                      type: string
                    buttonText:
                      type: string
                    required:
                      description: >-
                        Require an answer before submit. ONLY `text` supports
                        this — nps / rating / choice cannot be marked required.
                      type: boolean
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - multiline
                - type: object
                  properties:
                    kind:
                      type: string
                      enum:
                        - choice
                    name:
                      type: string
                      description: >-
                        The question's internal name / analytics label (it is
                        the `questionName` on captured responses). It is NOT
                        rendered to the user — the widget shows only the input
                        (scale / options / text field), not this string. To show
                        a visible question prompt, add a `text` block in the
                        SAME step before the question block; a question with
                        only a `name` renders as bare options with no question
                        text.
                    cvid:
                      type: string
                    options:
                      type: array
                      items:
                        type: object
                        properties:
                          label:
                            type: string
                          value:
                            type: string
                        required:
                          - label
                          - value
                      description: >-
                        Each option has a human-facing `label` and a stored
                        `value` — the `value` is what gets recorded/bound as the
                        answer.
                    allowMultiple:
                      type: boolean
                      description: >-
                        false = single-select, true = multi-select. A
                        multi-select answer needs a `list`-typed bound
                        attribute.
                    enableOther:
                      type: boolean
                    otherPlaceholder:
                      type: string
                    shuffle:
                      type: boolean
                    buttonText:
                      type: string
                    bindAttribute:
                      description: >-
                        Optional: codeName of an EXISTING attribute (create the
                        attribute definition first) to ALSO save this answer
                        onto the user for targeting/segmentation — use the
                        codeName, NOT the id. The write does not check it, but
                        the version validation WARNS when the attribute is
                        missing or its dataType mismatches the answer — read
                        warnings. A wrong code that slips through silently
                        captures nothing at runtime. Match the attribute
                        dataType to the answer: number (nps / rating), string
                        (single-select choice), list (multi-select choice).
                        Leaving it unset still records the answer as a response
                        event — bind only when you need to target/segment on it.
                      type: string
                  required:
                    - kind
                    - name
                    - options
                    - allowMultiple
            actions:
              description: >-
                Actions that fire when this question is answered (on pick for
                nps/rating/single-select; on its Submit button for
                text/multi-select). Put a `goto_step` HERE to advance to the
                next step — without it the question records the answer but the
                flow does NOT advance (validate flags the next step "not
                reachable"). Do NOT add a separate `button` block just to
                advance: it doubles up with the question's own submit
                affordance.
              type: array
              items:
                oneOf:
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - goto_step
                      step:
                        type: string
                        description: >-
                          Target step: a step `key` declared elsewhere in the
                          same write, or an existing step cvid. Resolved
                          server-side to the cvid.
                    required:
                      - type
                      - step
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - start_content
                      content:
                        type: string
                        description: >-
                          contentId of the flow or checklist to launch (an id
                          from the content list) — a raw content id, NOT a step
                          key (unlike goto_step). Must reference a flow or
                          checklist (a banner / launcher / resource-center /
                          tracker is rejected at write). The target must be
                          PUBLISHED to actually start at runtime; an
                          unknown/dangling id is rejected at validate.
                      step:
                        description: >-
                          Optional cvid of a step within the launched flow to
                          start at.
                        type: string
                    required:
                      - type
                      - content
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - navigate
                      url:
                        type: string
                        description: >-
                          Absolute URL, or an app-relative path ("/docs/x")
                          resolved against the origin the user is on — relative
                          paths are the normal choice for in-app navigation.
                      newTab:
                        description: >-
                          Open the URL in a new browser tab instead of
                          navigating the current one.
                        type: boolean
                    required:
                      - type
                      - url
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - dismiss
                    required:
                      - type
                    description: >-
                      Dismiss the piece the action lives on. NOT accepted
                      everywhere this union appears: a resource center has no
                      dismiss (closing the panel is a UI affordance, not an
                      action) and an announcement is marked seen, never
                      dismissed — writes there are rejected (E1017), not
                      ignored. Flows / checklists / launchers / banners all
                      accept it.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - run_javascript
                      script:
                        type: string
                    required:
                      - type
                      - script
                    description: >-
                      Read-back of an existing script action — scripts are not
                      authorable through this API. Echo it back UNCHANGED (same
                      script) when rewriting the surrounding list and the stored
                      action is preserved; omitting it deletes it (action lists
                      are full replacements). Authoring a new or edited script
                      is rejected.
                  - type: object
                    properties:
                      type:
                        type: string
                        enum:
                          - unsupported
                      note:
                        type: string
                    required:
                      - type
                    description: >-
                      Echo-only placeholder for a stored action this schema
                      cannot express (`note` = internal type). Echo it back to
                      preserve the stored action; writing one fresh is rejected.
          required:
            - type
            - question
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - columns
            columns:
              type: array
              items:
                type: object
                properties:
                  width:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum:
                          - percent
                          - pixels
                          - fill
                      value:
                        type: number
                        minimum: 0
                    required:
                      - unit
                  justify:
                    description: >-
                      Horizontal alignment of this column's own block(s) within
                      the column's width — use "end"/"center" to right-align or
                      center a lone button (a single-column `columns` block).
                    type: string
                    enum:
                      - start
                      - center
                      - end
                      - between
                      - around
                      - evenly
                  align:
                    type: string
                    enum:
                      - start
                      - center
                      - end
                      - baseline
                  padding:
                    type: object
                    properties:
                      enabled:
                        type: boolean
                      top:
                        type: number
                      bottom:
                        type: number
                      left:
                        type: number
                      right:
                        type: number
                  blocks:
                    type: array
                    items:
                      $ref: '#/components/schemas/ContentVersionDto__schema0'
                required:
                  - blocks
              description: >-
                One entry per column, laid out left-to-right. Each column is a
                mini vertical stack of `blocks` (usually one).
          required:
            - type
            - columns
          description: >-
            Lays 2+ blocks out side by side in one row. Top-level `content`
            blocks otherwise stack vertically — each is its own full-width row —
            so two `button` blocks placed directly in `content` render as two
            stacked rows, NOT a button pair. For a modal/tooltip footer with a
            Skip + primary button: one `columns` block with two `{ width: {
            unit: "fill" }, blocks: [...] }` entries, one button per column.
        - type: object
          properties:
            object:
              default: block
              type: string
              enum:
                - block
            id:
              type: string
            type:
              type: string
              enum:
                - unsupported
            note:
              type: string
          required:
            - type
    ContentVersionDto__schema1:
      oneOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - group
            match:
              type: string
              enum:
                - all
                - any
            conditions:
              minItems: 1
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema1'
              description: >-
                The grouped conditions — at least one. An EMPTY group is not "no
                filter": it never matches, so next to an AND it makes the whole
                rule unmatchable, and writing one is rejected. A version saved
                with an empty group in the BUILDER still reads back with it
                (validate warns); writing that list back is refused until the
                group is filled or dropped.
          required:
            - type
            - match
            - conditions
        - type: object
          properties:
            type:
              type: string
              enum:
                - attribute
            scope:
              type: string
              enum:
                - user
                - company
                - companyMembership
              description: >-
                Which entity owns the attribute — `user` (the end user),
                `company`, or `companyMembership`. Same value as the attribute
                definition's `scope` (see the attribute definitions list);
                required to disambiguate a codeName that exists in more than one
                scope.
            attribute:
              type: string
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - any
                - empty
                - lt
                - lte
                - gt
                - gte
                - between
                - 'true'
                - 'false'
                - includes_any
                - includes_all
                - not_includes_any
                - not_includes_all
                - less_than
                - exactly
                - more_than
                - before
                - 'on'
                - after
              description: >-
                Operator — the allowed set depends on the attribute dataType.
                String: is | not | contains | not_contains | starts_with |
                ends_with | any | empty. Number: is | not | lt | lte | gt | gte
                | between | any | empty. Boolean: true | false | any | empty.
                List: includes_any | includes_all | not_includes_any |
                not_includes_all | any | empty. DateTime: less_than | exactly |
                more_than (relative — `value` is a number of days) | before | on
                | after (`value` is an absolute date) | any | empty. The
                relative ops are ONE-SIDED bounds around (now − N days):
                `less_than N` = the date is AFTER now−N — so it also matches
                every FUTURE date, and on a future-dated attribute (a trial end,
                a renewal date) it is NOT "within the last N days"; `more_than
                N` = the date is BEFORE now−N. **"Signed up in the last N days"
                therefore needs BOTH bounds** — `less_than N` AND `more_than 0`
                in one `all` group; `less_than N` alone silently includes anyone
                whose date is in the future (a mis-mapped trial-end column, a
                clock/timezone slip), and those are exactly the users a new-user
                audience must not contain (observed in testing). Negative N
                shifts the bound into the future: the rolling "within the NEXT 7
                days" window is `less_than` value "0" AND `more_than` value "-7"
                (two conditions, both required). The relative ops are
                DAY-granularity only — no unit field; for hour/minute windows
                use an `event` condition with a `within` (which has a `unit`).
            value:
              description: >-
                The comparison value (string / number-as-string / date). Omit
                for any/empty/true/false.
              type: string
            value2:
              description: >-
                Upper bound for the `between` operator (`value` is the lower
                bound).
              type: string
            values:
              description: Values for the List operators (includes_any / includes_all / …).
              type: array
              items:
                type: string
          required:
            - type
            - scope
            - attribute
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - segment
            segment:
              type: string
            in:
              type: boolean
          required:
            - type
            - segment
            - in
        - type: object
          properties:
            type:
              type: string
              enum:
                - current_url
            includes:
              type: array
              items:
                type: string
              description: >-
                URL patterns (anchored whole-url match, NOT substring/regex).
                `*` = wildcard within one url part; `:name` = one path segment.
                A bare `*` (i.e. `["*"]`) matches EVERY page on every host incl.
                deep paths — the canonical always-on / whole-site pattern (use
                it when content should be available everywhere). Scope it down
                instead with: `*/` (homepage only — path exactly `/`),
                `*/pricing` (one page), `*/app/*` (a section + below),
                `host.com/*` (any page on a specific host). Multiple patterns
                are OR-matched: the URL matches this list if it matches ANY one
                pattern (so "/tasks OR /dashboard" is one condition with both
                patterns here — no group needed).
            excludes:
              description: >-
                URL patterns to exclude (same syntax as includes); excludes win
                over includes.
              type: array
              items:
                type: string
          required:
            - type
            - includes
        - type: object
          properties:
            type:
              type: string
              enum:
                - element
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
            state:
              type: string
              enum:
                - present
                - hidden
                - disabled
                - enabled
                - clicked
                - unclicked
              description: >-
                `present` means NOT CLIPPED AWAY: the element is in the DOM and
                its box lies inside the viewport / its scroll ancestors —
                scrolled off-screen or `display:none` never satisfies it (and
                `hidden` is its negation). It is NOT "the user can see something
                there": an EMPTY, zero-height placeholder node satisfies
                `present` (observed in testing: a checklist task keyed on an
                initially-empty `<p>` status line ticked itself the moment the
                checklist appeared, before the shopper did anything). So do not
                use element presence as a proxy for "the app has said
                something": most apps keep the container mounted and only fill
                in its text. Match the TEXT instead (`target.text` + `present`,
                or the negation trick: the old text `hidden`). Appearances
                shorter than about a second can be missed entirely.
                `disabled`/`enabled` read the element disabled state at
                evaluation time. **`clicked` means "clicked since page load AND
                the element is STILL in the DOM right now"** — both halves,
                re-checked every evaluation. The click memory latches (the
                listener attaches the FIRST time the condition is evaluated, so
                earlier clicks are invisible, and the memory survives a
                re-render), but the element lookup is redone each poll. Two
                consequences, one of them silent: (1) **an element that UNMOUNTS
                on click can NEVER satisfy it** — the click lands, the element
                vanishes, the lookup fails from then on and the condition stays
                false forever with no error (observed in testing: a tracker on a
                button that clears its own toolbar counted ZERO real clicks);
                (2) an element that unmounts and REMOUNTS satisfies it again, so
                a tracker gated on it fires once per remount — not once per page
                load. Unlike `present`, this lookup does NOT require viewport
                visibility: scrolling the target off-screen keeps `clicked`
                true. `unclicked` negates the same pair, so it is also false
                while the element is absent. To count a COMPLETED action,
                condition on what the app shows afterwards (a success toast, a
                state change) rather than `clicked` on the button that starts
                it.
          required:
            - type
            - state
        - type: object
          properties:
            type:
              type: string
              enum:
                - content_state
            content:
              type: string
              description: >-
                contentId of the FLOW or CHECKLIST whose per-user state to check
                (an id from the content list). Only flows and checklists record
                this state — referencing a banner / launcher / resource-center /
                tracker is rejected at write.
            state:
              type: string
              enum:
                - seen
                - unseen
                - completed
                - uncompleted
                - active
                - inactive
              description: >-
                The referenced flow/checklist's state for THIS user. seen =
                started at least once (for a flow, TRUE from the moment it
                opens; for a checklist, TRUE only once the user EXPANDS the
                panel — a `initialDisplay: "button"` checklist whose launcher is
                never clicked stays unseen forever); unseen = never started;
                active = currently open/running; inactive = NOT currently
                running (covers both never-started and ran-then-closed);
                completed = reached a goal/completion step; uncompleted = not
                completed. To gate piece B until flow A has run AND closed (the
                usual "show next thing after the welcome flow" sequencing), use
                `seen` AND `inactive` together — `seen` alone fires while A is
                still open (B piles on top), and `completed` alone strands users
                who skip/dismiss A.
          required:
            - type
            - content
            - state
        - type: object
          properties:
            type:
              type: string
              enum:
                - event
            event:
              type: string
            count:
              description: >-
                How many times the event must have occurred. Omit it for the
                common case "the event has happened" (treated as at_least 1).
                Set `op`/`n` for a threshold (`between` needs `n` and `n2`).
                `at_least`/`between` require n ≥ 1; use `at_most`/`exactly` with
                0 for "never happened".
              type: object
              properties:
                op:
                  type: string
                  enum:
                    - at_least
                    - at_most
                    - exactly
                    - between
                'n':
                  type: integer
                  minimum: 0
                  maximum: 9007199254740991
                n2:
                  type: integer
                  minimum: 0
                  maximum: 9007199254740991
              required:
                - op
                - 'n'
            within:
              description: >-
                Optional time window for the event count. Omit it (or use
                `any_time`) to count over all time — "the event has ever
                happened". Any other `op` (`in_the_last` / `more_than` /
                `between`) requires BOTH `value` and `unit`, and `between` also
                `value2` — rejected at write otherwise.
              type: object
              properties:
                op:
                  type: string
                  enum:
                    - in_the_last
                    - more_than
                    - between
                    - any_time
                value:
                  type: number
                value2:
                  type: number
                unit:
                  type: string
                  enum:
                    - seconds
                    - minutes
                    - hours
                    - days
              required:
                - op
            scope:
              description: >-
                Whose event activity to count (default `current_user`).
                `current_user` = only this user's own events.
                `current_user_in_company` = this user's events, but counted
                within their currently-associated company context (needs the
                user associated to a company via `group()` / the
                company-membership API). `any_user_in_company` = events by ANY
                user in this user's company — account-level activity (e.g.
                "anyone on the account has done X"). The two company scopes
                require the user to be in a company or they never match.
              type: string
              enum:
                - current_user
                - current_user_in_company
                - any_user_in_company
            where:
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema2'
          required:
            - type
            - event
        - type: object
          properties:
            type:
              type: string
              enum:
                - text_input
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - match
                - unmatch
                - any
                - empty
            value:
              type: string
          required:
            - type
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - text_filled
            target:
              type: object
              properties:
                selector:
                  type: string
                  minLength: 1
                  description: >-
                    A stable CSS selector for the element. The runtime targets
                    the FIRST match — so either make the selector unique, or
                    pair a stable non-unique selector with `nth` to pick the
                    intended match. A non-unique selector with no `nth` targets
                    the first (often wrong) element and the tooltip silently
                    won't render.
                text:
                  description: >-
                    Optional refinement of `selector`. Requires the targeted
                    element's visible text to equal this (exact match, after
                    trim) — use it to pin a specific content/state (e.g. a
                    stable id whose displayed text you want to match: id +
                    text). It refines the element chosen by `selector`/`nth`; on
                    its own it does NOT search among multiple matches, so
                    disambiguate a non-unique selector with `nth`, not `text`
                    alone.
                  type: string
                nth:
                  description: >-
                    Optional refinement of `selector`. 0-based index to pick
                    which match when the selector isn't unique — e.g. a stable
                    selector matching 3 elements + `nth: 1` targets the 2nd,
                    giving a unique result. Matches are taken in document order
                    (as they appear in the page HTML). Range 0–4 — only the
                    first 5 matches are addressable; a larger value is rejected.
                  type: integer
                  minimum: 0
                  maximum: 4
              required:
                - selector
          required:
            - type
        - type: object
          properties:
            type:
              type: string
              enum:
                - time_window
            start:
              type: string
              description: >-
                Window start (ISO datetime). REQUIRED — the runtime never
                matches a window without a start, so an end-only window is
                rejected at write. For "until X" semantics, set start to any
                past instant and end to X.
            end:
              description: >-
                Window end (ISO datetime). Omit for an open-ended "from start
                onwards" window.
              type: string
          required:
            - type
            - start
        - type: object
          properties:
            type:
              type: string
              enum:
                - unsupported
            note:
              type: string
          required:
            - type
          description: >-
            Read-side placeholder for a stored condition this API cannot express
            (`note` says what it stands for — usually a DEAD condition the
            runtime never matches: a deleted attribute/event, an end-only time
            window). It cannot be written back (the placeholder carries no data
            to preserve): echoing it is rejected. Either remove it from the list
            you write — an explicit choice that DELETES the stored condition;
            mind that a never-matching node inside an AND list pins the whole
            rule to "never fires", so deleting it can bring the remaining
            conditions to life — or repair the original condition in the
            Usertour builder first.
    UpdateVersionBodyDto__schema2:
      oneOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - event_attribute
            attribute:
              type: string
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - any
                - empty
                - lt
                - lte
                - gt
                - gte
                - between
                - 'true'
                - 'false'
                - includes_any
                - includes_all
                - not_includes_any
                - not_includes_all
                - less_than
                - exactly
                - more_than
                - before
                - 'on'
                - after
            value:
              type: string
            value2:
              type: string
            values:
              type: array
              items:
                type: string
          required:
            - type
            - attribute
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - group
            match:
              type: string
              enum:
                - all
                - any
            conditions:
              minItems: 1
              type: array
              items:
                $ref: '#/components/schemas/UpdateVersionBodyDto__schema2'
              description: >-
                The grouped conditions — at least one. An EMPTY group is not "no
                filter": it never matches, so next to an AND it makes the whole
                rule unmatchable, and writing one is rejected. A version saved
                with an empty group in the BUILDER still reads back with it
                (validate warns); writing that list back is refused until the
                group is filled or dropped.
          required:
            - type
            - match
            - conditions
    ContentVersionDto__schema2:
      oneOf:
        - type: object
          properties:
            type:
              type: string
              enum:
                - event_attribute
            attribute:
              type: string
            op:
              type: string
              enum:
                - is
                - not
                - contains
                - not_contains
                - starts_with
                - ends_with
                - any
                - empty
                - lt
                - lte
                - gt
                - gte
                - between
                - 'true'
                - 'false'
                - includes_any
                - includes_all
                - not_includes_any
                - not_includes_all
                - less_than
                - exactly
                - more_than
                - before
                - 'on'
                - after
            value:
              type: string
            value2:
              type: string
            values:
              type: array
              items:
                type: string
          required:
            - type
            - attribute
            - op
        - type: object
          properties:
            type:
              type: string
              enum:
                - group
            match:
              type: string
              enum:
                - all
                - any
            conditions:
              minItems: 1
              type: array
              items:
                $ref: '#/components/schemas/ContentVersionDto__schema2'
              description: >-
                The grouped conditions — at least one. An EMPTY group is not "no
                filter": it never matches, so next to an AND it makes the whole
                rule unmatchable, and writing one is rejected. A version saved
                with an empty group in the BUILDER still reads back with it
                (validate warns); writing that list back is refused until the
                group is filled or dropped.
          required:
            - type
            - match
            - conditions
  securitySchemes:
    bearer:
      scheme: bearer
      bearerFormat: utp_... personal API token (opaque)
      type: http

````