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

# Publish a version

> Release the draft config as the next version, through the eval gate. Organization API keys only.

## Behavior

This request runs the instance's `gate` eval scenarios with real model calls before it releases anything, and can take up to 50 minutes. It is exempt from the 30-second request timeout; keep the connection open. The gate rules, every outcome, and the waiver are on [Versions and publish](/conversations/versions-and-publish).


## OpenAPI

````yaml POST /api/v1/conversation-instances/{instance_slug}/versions
openapi: 3.1.0
info:
  title: Nexio API
  version: '1.0'
  description: |
    The Nexio public API. Submit runs to configured engines and read their
    results, hold conversations with configured assistants, make authorized
    reads over the planes and families of a connected system of record, and
    manage webhooks and environments.

    Six engine types are registered: comparison, matching, entity_analysis,
    diligence, triage, and opportunity.

    Every route under /api/v1/ requires `Authorization: Bearer <key>`, except
    inbound event ingest (`POST /api/v1/events/ingest/{source_key}`), which
    authenticates each request against its ingest source instead: an
    HMAC-SHA256 signature for `nexio` and `github` sources, or a shared
    authentication code for an `ams360_ons` source. Error
    bodies share the `Error` schema. Call the API from servers only: it sends
    no CORS headers.
  contact:
    email: support@usenexio.com
    url: https://docs.usenexio.com
servers:
  - url: https://api.usenexio.com
    description: >-
      Nexio API. Sandbox or live is chosen by the API key's environment, not by
      the host.
security:
  - BearerAuth: []
tags:
  - name: EngineManagement
    description: >-
      Create, configure, version and manage engines. An engine is a
      configuration of one registered engine type.
  - name: Engines
    description: Engine-scoped endpoints for submitting runs and retrieving results.
  - name: Runs
    description: Retrieve and reconcile submitted runs.
  - name: Records
    description: >-
      Typed, authorized reads over the registered planes and families of a
      connected system of record, and governed writes to the action ledger. The
      generic family read is the core contract.
  - name: Graph
    description: >-
      The organization's data graph: a read-only map of connections and the
      derivations scheduled on them. Node kinds are a closed registry of 16; the
      API serves 14.
  - name: Environments
    description: >-
      The live environment and up to 5 sandbox environments in your org.
      Organization keys only.
  - name: Webhooks
    description: >-
      Manage webhook endpoints that receive terminal run events (run.completed,
      run.failed, run.cancelled) and run corrections (run.superseded).
  - name: Events
    description: >-
      Send inbound events to your organization's event log through an ingest
      source. Source kinds are nexio, github and ams360_ons; a nexio source
      sends event types from your own vocabulary.
  - name: Converse
    description: The raw stateless conversational model turn (caller-owned state).
  - name: Conversations
    description: >-
      Conversation instances (orchestrators over engines) and their managed
      conversations, turns, annotations, evals, and exports.
  - name: Platform
    description: Service health. No key needed.
paths:
  /api/v1/conversation-instances/{instance_slug}/versions:
    parameters:
      - $ref: '#/components/parameters/InstanceSlug'
    post:
      tags:
        - Conversations
      summary: Publish an instance version
      description: >
        Releases the instance's live draft config as the next integer

        version. The live draft is revalidated first, so drafts saved by an

        older client with retired model selectors fail with

        `invalid_instance_config`. When the instance carries active `gate`-suite
        eval scenarios

        and the draft differs from the latest release, the publish is GATED:
        every such

        scenario replays against the candidate

        config with real model calls before anything is released, the run is

        recorded against the candidate, and the per-instance

        `evals.on_regression` policy decides `block` (publish refuses with

        the per-scenario diff, `conversation_eval_regressed`) or `warn`

        (publish proceeds, result recorded). An explicit waiver (`waived_by`

        + `waive_reason`, always together) bypasses a block and is recorded

        on the run row; a waiver sent when nothing is blocked is ignored. A
        concurrent config save between the gate and the

        release refuses with `config_changed_during_publish`, and a `gate`-suite

        scenario created, edited, or deleted while the gate ran refuses with

        `scenario_set_changed_during_publish` (nothing is released in either

        case). Re-publishing an unchanged config returns the current

        latest version with `already_released: true`. Followers reject with

        `instance_follows_canonical`. Organization API keys only: every scoped
        key is refused with

        `403 insufficient_capability`. The route is exempt from the 30 second

        request timeout; the gate plus release is bounded at 50 minutes.

        The gate runs only `gate`-suite scenarios. An archived instance can

        still be published.
      operationId: publishConversationInstanceVersion
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                changelog:
                  type: string
                waived_by:
                  type: string
                waive_reason:
                  type: string
      responses:
        '200':
          description: >-
            The released version (or the idempotent no-op). `released_at` has
            whole-second precision. On a new release it is the time the response
            was built and can differ slightly from the version list. When
            `already_released` is true, `changelog` and `published_by` are the
            latest version's, not this request's.
          content:
            application/json:
              schema:
                type: object
                required:
                  - version
                  - config_hash
                  - released_at
                  - changelog
                properties:
                  version:
                    type: integer
                  config_hash:
                    type: string
                  released_at:
                    type: string
                    format: date-time
                  changelog:
                    type: string
                  already_released:
                    type: boolean
                  published_by:
                    type: string
        '400':
          description: |
            The slug in the path is blank or the body is not JSON or is over
            1 MiB (`invalid_request`), only one of `waived_by` and
            `waive_reason` was sent (`invalid_eval_waiver`; a value of only
            spaces counts as not sent), or the draft fails revalidation
            (`invalid_instance_config`, with `details` as
            `[{path, message}]`). A bad body on an unknown slug answers 404,
            and on a follower answers 409 `instance_follows_canonical`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/OrganizationKeyRequired'
        '404':
          description: >-
            `instance_not_found`: no live instance with this slug in the
            organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: |
            No live config to publish (`instance_config_hash_missing`), the
            instance follows a platform-managed source instance
            (`instance_follows_canonical`), the config changed while the
            eval gate ran (`config_changed_during_publish`), or the eval
            scenario set changed while the gate ran
            (`scenario_set_changed_during_publish`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: |
            The candidate regressed the instance's Conversation eval set
            under `on_regression: block` (`conversation_eval_regressed`).
            Regression is per scenario and is judged against the gate run
            recorded for the latest released version: a scenario that passed
            there and now fails, or a scenario with no result there that
            fails, blocks. When the latest version has no recorded gate run
            (for example the first publish with scenarios), the run is the
            baseline and never blocks. The failing run is still recorded. The
            `details` object carries `pass_count`, `fail_count`,
            `prior_pass_count`, `newly_failing` (regressions), `new_failing`
            (newly added failing scenarios), `newly_passing`, and
            `eval_run_id`; publish with an explicit waiver or fix the config.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          description: >-
            The publish failed (`internal_error` when the instance lookup
            failed, `publish_failed` for any later step, `auth_context_missing`
            before the route ran); nothing was released.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: >-
            The eval gate could not execute a scenario
            (`conversation_eval_execution_failed`); nothing was recorded or
            released.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >
            The instance has active `gate`-suite eval scenarios and a draft that
            differs from the latest release, but no eval executor is available
            (`conversation_eval_gate_unavailable`); the gate cannot run and the
            publish fails closed.


            Also `auth_unavailable`: API key authentication was briefly
            unavailable before the route ran. That cause is transient; retry it
            with backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  parameters:
    InstanceSlug:
      name: instance_slug
      in: path
      required: true
      description: Conversation instance identifier slug (e.g. `platform-assistant`).
      schema:
        type: string
  schemas:
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: >
            Stable snake_case error identifier. Safe to match programmatically.

            New codes are added over time; treat an unknown code by its HTTP
            status.


            Known codes include:

            `invalid_request`, `invalid_input`, `unauthorized`,

            `auth_unavailable`, `rate_limited`, `missing_run_id`,

            `invalid_run_id`, `run_not_found`, `invalid_offerings`,

            `missing_input`, `queue_unreachable`, `engine_not_found`,

            `engine_slug_conflict`, `engine_archived`, `instance_not_found`,

            `instance_slug_conflict`, `instance_archived`,

            `instance_follows_canonical`, `instance_not_published`,

            `invalid_engine_type`, `validation_error`, `webhook_not_found`,

            `webhook_limit_exceeded`, `invalid_url`, `invalid_events`,

            `invalid_description`, `invalid_auth_token`,

            `missing_endpoint_id`, `invalid_endpoint_id`,

            `missing_delivery_id`, `invalid_delivery_id`,

            `delivery_not_found`, `delivery_not_resendable`,

            `insufficient_capability`, `engine_version_required`,

            `engine_version_exact_required`, `engine_version_not_found`,

            `engine_version_invalid_format`,

            `engine_version_draft_requires_sandbox_key`,

            `engine_version_none_released`, `test_scenario_sandbox_only`,

            `test_scenario_forbidden`, `test_scenario_exact_version_required`,

            `test_scenario_version_not_supported`, `invalid_test_scenario`,

            `request_bound_exceeded`, `run_cap_exceeded`,

            `scoped_key_required`, `engine_binding_forbidden`,

            `request_timeout`, `internal_error`, `idempotency_key_reused`,

            `invalid_idempotency_key`, `acting_principal_mismatch`,

            `run_requires_acting_principal`, `environment_slug_invalid`,

            `environment_slug_reserved`, `environment_slug_taken`,

            `environment_name_invalid`, `environment_limit_reached`,

            `environment_live_immutable`, `environment_not_found`,

            `environment_in_use`, `environment_operation_failed`,

            `list_environments_failed`, `engine_release_unservable`,

            `engine_config_hash_inconsistent`,

            `engine_config_hash_unavailable`,

            `engine_config_version_unavailable`,

            `engine_version_resolve_failed`,

            `engine_config_version_load_failed`,

            `engine_version_publish_mismatch`,

            `engine_version_schema_change_requires_major`,

            `engine_config_hash_missing`, `engine_config_changed`,

            `invalid_engine_config`, `cold_start_gate_not_met`,

            `cold_start_gate_failed`, `cold_start_gate_regressed`,

            `cancel_run_failed`, `event_id_reused`, `invalid_event_id`,

            `missing_event_id`, `invalid_event_type`, `invalid_payload`,

            `reason_text_too_long`, `reason_taxonomy_version_unknown`,

            `invalid_rating`, `missing_comment`, `invalid_target`,

            `invalid_time_on_task`, `scoped_annotation_required`,

            `missing_instance_slug`, `invalid_instance_config`,

            `invalid_eval_waiver`, `instance_config_hash_missing`,

            `config_changed_during_publish`,

            `scenario_set_changed_during_publish`,

            `conversation_eval_regressed`,

            `conversation_eval_execution_failed`,

            `conversation_eval_gate_unavailable`, `publish_failed`,

            `conversation_not_found`, `conversation_archived`,

            `invalid_cursor`, `message_not_found`, `invalid_turn_request`,

            `message_too_long`, `invalid_tool_result`, `invalid_confirmation`,

            `invalid_edit_target`, `turn_in_progress`, `pending_turn`,

            `turn_state_conflict`, `confirmation_environment_unpinned`,

            `instance_config_missing`, `instance_config_invalid`,

            `instance_model_unavailable`, `guardrail_evaluation_failed`,

            `guardrail_config_invalid`, `invalid_conversation_history`,

            `streaming_unsupported`, `converse_unavailable`, `provider_error`,

            `provider_unavailable`, `unknown_model`, `too_many_messages`,

            `too_many_tools`, `invalid_max_tokens`, `invalid_message_role`,

            `invalid_message`, `invalid_content_block`, `invalid_tool`,

            `attachments_not_enabled`, `attachments_unavailable`,

            `attachment_rejected`, `attachment_too_large`,

            `attachments_too_large`, `too_many_attachments`,

            `attachment_not_accepted`, `attachment_not_found`,

            `attachment_changed`, `attachment_read_failed`,

            `attachment_member_delete`, `attachment_not_reservable`,

            `invalid_offset`, `invalid_turn_id`, `invalid_comment`,

            `invalid_reason`, `invalid_feedback_key`, `turn_not_found`,

            `annotation_not_found`, `annotation_not_promotable`,

            `invalid_eval_scenario`, `conversation_eval_scenario_not_found`,

            `conversation_eval_scenario_cap`,

            `conversation_eval_run_not_found`,

            `conversation_eval_baseline_not_found`,

            `conversation_eval_unavailable`,

            `instance_version_invalid_format`, `instance_version_not_found`,

            `document_class_not_open`, `presign_failed`,

            `markets_directory_unavailable`, `book_unavailable`,

            `book_connection_ambiguous`, `identity_unmapped`,

            `identity_needs_review`, `identity_suspended`, `identity_stale`,

            `scope_unavailable`, `assertion_invalid`, `assertion_stale`,

            `cursor_filter_mismatch`, `cursor_expired`,

            `action_schema_unknown`, `action_payload_invalid`,

            `action_out_of_scope`, `action_list_too_large`,

            `overlay_read_only`, `unsupported_node_type`,

            `acting_principal_required`, `action_denied`,

            `appetite_read_denied`, `approval_required`,

            `catalog_access_denied`, `catalog_connection_ambiguous`,

            `create_webhook_failed`, `dataset_denied`, `delivery_id_reused`,

            `document_type_not_servable`, `document_unclassified`,

            `egress_manifest_version_mismatch`,

            `egress_manifest_version_required`, `event_type_not_allowed`,

            `event_type_reserved`, `execution_confirm_required`,

            `execution_prohibited`, `ingest_source_disabled`,

            `ingest_source_misconfigured`, `ingest_source_not_found`,

            `invalid_acting_assertion`, `invalid_active`,

            `invalid_credentials`, `invalid_payload_mode`,

            `invalid_signature`, `load_run_failed`, `load_solutions_failed`,

            `load_work_items_failed`, `missing_engine_slug`, `not_found`,

            `object_store_unconfigured`, `provider_not_approved`,

            `resolve_retry_exhausted`, `run_lookup_failed`,

            `service_identity_unknown`, `stale_timestamp`, `surface_denied`,

            `unresolved_market_question`, `unsupported_market_filter`.


            The full list with causes and fixes is at

            https://docs.usenexio.com/reference/errors.
        message:
          type: string
          description: Human-readable error message. May change between versions.
        details:
          description: |
            Optional request-specific details. Request-bound failures use the
            `RequestBoundDetails` object. Validation failures may use an array
            of field issues or another documented object.

            `409 environment_in_use` is the one exception to this envelope: it
            carries a top-level `blockers` object (see `EnvironmentInUseError`)
            instead of `details`.
  responses:
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: unauthorized
            message: Missing or invalid API key
    OrganizationKeyRequired:
      description: >-
        This route accepts organization keys only. Every scoped key gets this
        answer, whatever capabilities it holds.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: insufficient_capability
            message: API key does not have permission for this action
    RateLimited:
      description: Rate limit exceeded. Retry after the window resets.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: rate_limited
            message: Rate limit exceeded
  headers:
    RetryAfter:
      description: Whole seconds to wait before retrying, at least 1.
      schema:
        type: integer
        minimum: 1
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >
        Send the key as `Authorization: Bearer <key>`. Two kinds of key exist.


        Organization keys are issued in the portal (Settings, then API keys),

        each bound to one environment, shaped `nx_<environment slug>_<64 hex>`.
        They carry

        no capabilities and pass every capability check, with one exception:

        routes under /api/v1/records, /api/v1/engines/{id}/opportunities,

        /api/v1/graph and /api/v1/catalog/documents accept an

        organization key only when its environment is `live`, and refuse any

        other with 403 `scoped_key_required`. Revocation takes effect within 60

        seconds.


        Scoped keys are issued by Nexio on request, shaped

        `nxsk_v1_<24 hex key id>_<43 character secret>`. Each is bound to one

        org, one environment, a set of engines and a set of capabilities. A

        malformed, unknown or revoked `nxsk_` key fails with 401 and is never

        retried as an organization key. Revocation takes effect on the next

        request. A scoped key without a route's capability gets 403

        `insufficient_capability`; a scoped key not bound to the engine gets 403

        `engine_binding_forbidden`.


        Key-grantable capabilities: `engines:read`, `runs:write`, `runs:read`,

        `runs:defensibility:read`, `runs:test`, `catalog:read`,

        `catalog:documents:read`, `webhooks:manage`, `conversations:use`,

        `conversations:export`, `records:read`, `records:opportunities:run`,

        `actions:write`, `actions:read`, `graph:read`, `records:analyze`.


        Routes that accept organization keys only (every scoped key gets 403

        `insufficient_capability`): environment management, engine create,

        update, configuration and publish, and conversation instance

        authoring. Each operation description names the capability a scoped

        key needs.

````