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

# update_workspace

> Change a workspace's mutable configuration. Cost class: fast.

Presence-aware, and whole-block: an omitted field is left alone, a supplied
one replaces its block entirely. Read the workspace, edit the block, send it
back — partial blocks fall back to the schema defaults, which is how a caller
flipping ``auto_build`` would otherwise wipe its own exclusion rules.

Graph builds are explicit by default: a build happens when
``POST /v1/workspaces/{id}/knowledge-graph/builds`` asks for one. Turning
``knowledge_graph.auto_build`` on hands that trigger to ingestion instead, for
a workspace that wants a graph over everything it ingests and accepts the bill
for one per ingestion. Either way a build already in flight is unaffected —
cancel it if that is what you meant.

``currency`` follows the same whole-block rule, so ``{}`` is how its policy is
cleared. Setting ``currency.default`` changes how the *next* ingestion reads
amounts marked with a symbol that names several currencies ($, ¥, kr);
amounts already extracted as ambiguous stay that way until their file is
re-ingested, because the catalog records what a past extraction could read.

The domain, the label list, and the workspace name are deliberately not
mutable here. The first two are part of the versioned config record stamped
onto every derived artifact, so editing them in place would re-describe
material that was derived under the old one.



## OpenAPI

````yaml /openapi.json patch /v1/workspaces/{workspace_id}
openapi: 3.1.0
info:
  description: >-
    Document intelligence: parse, split, classify, extract, and ground files, or
    build a searchable workspace. Authenticate with ``X-API-Key``.
  title: NDI Platform API
  version: 0.1.0
servers:
  - url: https://ndi-api.nace.ai
security: []
tags: []
paths:
  /v1/workspaces/{workspace_id}:
    patch:
      tags:
        - workspaces
      summary: update_workspace
      description: >-
        Change a workspace's mutable configuration. Cost class: fast.


        Presence-aware, and whole-block: an omitted field is left alone, a
        supplied

        one replaces its block entirely. Read the workspace, edit the block,
        send it

        back — partial blocks fall back to the schema defaults, which is how a
        caller

        flipping ``auto_build`` would otherwise wipe its own exclusion rules.


        Graph builds are explicit by default: a build happens when

        ``POST /v1/workspaces/{id}/knowledge-graph/builds`` asks for one.
        Turning

        ``knowledge_graph.auto_build`` on hands that trigger to ingestion
        instead, for

        a workspace that wants a graph over everything it ingests and accepts
        the bill

        for one per ingestion. Either way a build already in flight is
        unaffected —

        cancel it if that is what you meant.


        ``currency`` follows the same whole-block rule, so ``{}`` is how its
        policy is

        cleared. Setting ``currency.default`` changes how the *next* ingestion
        reads

        amounts marked with a symbol that names several currencies ($, ¥, kr);

        amounts already extracted as ambiguous stay that way until their file is

        re-ingested, because the catalog records what a past extraction could
        read.


        The domain, the label list, and the workspace name are deliberately not

        mutable here. The first two are part of the versioned config record
        stamped

        onto every derived artifact, so editing them in place would re-describe

        material that was derived under the old one.
      operationId: update_workspace_v1_workspaces__workspace_id__patch
      parameters:
        - description: Workspace identifier.
          in: path
          name: workspace_id
          required: true
          schema:
            description: Workspace identifier.
            format: uuid
            title: Workspace Id
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Workspace'
          description: Successful Response
        '504':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
          description: Gateway Timeout
        default:
          content:
            application/json:
              example:
                error:
                  code: invalid_request
                  detail: null
                  message: >-
                    Request body has extra fields that this operation does not
                    accept.
                  request_id: req-01j9k2n3p4q5r6s7t8v9
                  retryable: false
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
          description: >-
            Typed error envelope used by every 4xx and 5xx. ``error.code``
            distinguishes the failure; HTTP status is a consequence of the code.
      security:
        - APIKeyHeader: []
components:
  schemas:
    UpdateWorkspaceRequest:
      additionalProperties: false
      description: >-
        Change a workspace's mutable configuration.


        Presence-aware: a field omitted from the body is left exactly as it is,
        so a

        caller changing one block cannot clear another by not mentioning it. A
        field

        that *is* supplied replaces its block whole — the rule
        ``set_key_grants``

        follows for label grants, which is what keeps turning a policy off the
        same

        operation as turning it on, with no add/remove asymmetry to get wrong.


        Only the knowledge-graph policy and the currency policy are mutable
        today.

        The domain and the label list are not: both are part of the versioned
        config

        record that every derived artifact is stamped with, so editing them in
        place

        would silently re-describe material that was derived under the old one.
      properties:
        currency:
          anyOf:
            - $ref: '#/components/schemas/CurrencyPolicy'
            - type: 'null'
          description: >-
            The workspace's complete new currency-reading policy, or omitted to
            leave it unchanged. Whole-block like ``knowledge_graph``: an empty
            object resets to the USD default, and ``{"default": null}`` is how
            the policy is cleared to assume nothing. Applies from the next
            ingestion onwards: amounts already extracted as ambiguous stay that
            way until their file is re-ingested, since the catalog records what
            a past extraction could read.
        knowledge_graph:
          anyOf:
            - $ref: '#/components/schemas/KnowledgeGraphConfig'
            - type: 'null'
          description: >-
            The workspace's complete new knowledge-graph policy, or omitted to
            leave it unchanged. Supplying it replaces every field it holds, so
            send the block read back from the workspace with your edits applied
            rather than only the key you are changing.
      title: UpdateWorkspaceRequest
      type: object
    Workspace:
      additionalProperties: false
      description: >-
        A provisioned workspace, as the API returns it.


        Storage is provisioned for the caller and is not part of the wire
        contract:

        the root URI is an internal detail until customer-owned roots are
        exposed.
      properties:
        access:
          $ref: '#/components/schemas/AccessConfig'
        config_version:
          title: Config Version
          type: integer
        created_at:
          format: date-time
          title: Created At
          type: string
        currency:
          $ref: '#/components/schemas/CurrencyPolicy'
        domain_id:
          format: uuid
          title: Domain Id
          type: string
        domain_slug:
          title: Domain Slug
          type: string
        domain_version:
          title: Domain Version
          type: integer
        knowledge_graph:
          $ref: '#/components/schemas/KnowledgeGraphConfig'
        name:
          title: Name
          type: string
        purpose:
          anyOf:
            - $ref: '#/components/schemas/WorkspacePurpose'
            - type: 'null'
          description: >-
            Set when the platform provisioned this workspace on a person's
            behalf rather than at a caller's request. Such a workspace cannot be
            deleted. Null for every workspace created through this API.
        retention_policy:
          $ref: '#/components/schemas/RetentionPolicy'
        status:
          $ref: '#/components/schemas/WorkspaceStatus'
        updated_at:
          format: date-time
          title: Updated At
          type: string
        workspace_id:
          format: uuid
          title: Workspace Id
          type: string
      required:
        - workspace_id
        - name
        - domain_id
        - domain_slug
        - domain_version
        - access
        - retention_policy
        - knowledge_graph
        - currency
        - config_version
        - status
        - created_at
        - updated_at
      title: Workspace
      type: object
    ErrorEnvelope:
      description: Every non-2xx body on ``/v1``.
      example:
        error:
          code: invalid_request
          detail: null
          message: Request body has extra fields that this operation does not accept.
          request_id: req-01j9k2n3p4q5r6s7t8v9
          retryable: false
      properties:
        error:
          $ref: '#/components/schemas/Error'
      required:
        - error
      title: ErrorEnvelope
      type: object
    CurrencyPolicy:
      additionalProperties: false
      description: >-
        How this workspace's documents should be read where they leave a
        currency open.


        Extraction never converts an amount and never invents a currency: one
        whose

        currency the source does not state is recorded as ``ambiguous`` with no

        value, so it matches no amount filter. New workspaces default to

        ``DEFAULT_WORKSPACE_CURRENCY`` (USD), so a corpus that writes every
        total as a

        bare ``$900.00`` and names a currency nowhere is filterable out of the
        box.

        Set ``default`` to another ISO code to change the reading, or to
        ``null`` to

        assume nothing — an amount whose currency the source never states then
        stays

        ``ambiguous`` rather than being read as USD.
      properties:
        default:
          anyOf:
            - description: ISO 4217 code, e.g. 'USD'.
              pattern: ^[A-Z]{3}$
              type: string
            - type: 'null'
          default: USD
          description: >-
            Which currency to read when a document marks an amount with a symbol
            that names several currencies ($ for USD/CAD/AUD/…, ¥ for JPY/CNY,
            kr for SEK/NOK/…) and states no ISO code anywhere. Defaults to
            'USD'; set another ISO code to change it, or null to leave such an
            amount ambiguous (and so unfilterable). A resolved amount is
            recorded with 'currency_source: assumed' in the file's metadata so
            the assumption stays visible. It only ever disambiguates, never
            invents: an amount written '€900' is still EUR, a '$900' amount in a
            EUR-default workspace stays ambiguous (a dollar sign is not a way of
            writing euros), and an amount carrying no currency marker at all is
            never given one.
          title: Default
      title: CurrencyPolicy
      type: object
    KnowledgeGraphConfig:
      additionalProperties: false
      description: >-
        A workspace's knowledge-graph build policy.


        The defaults keep the whole corpus in scope but build nothing until
        asked: a

        graph is billable and runs for as long as the corpus takes, so it is not

        something ingestion should commit a caller to as a side effect. Set

        ``auto_build=true`` for a workspace that does want one after every
        ingestion.

        ``exclude_path_prefixes`` and ``exclude_categories`` are the
        workspace-wide

        skip rules a file's ``graph_inclusion`` can override — a file matching
        either

        is left out of the graph corpus unless it is explicitly ``include``\ d.
      properties:
        auto_build:
          default: false
          description: >-
            Build the graph automatically after each ingestion completes. Off by
            default: a build is billable and long-running, so it is requested
            rather than implied.
          title: Auto Build
          type: boolean
        exclude_categories:
          description: >-
            Files whose category is any of these are kept out of the graph
            corpus (override per file).
          items:
            maxLength: 1024
            type: string
          maxItems: 128
          title: Exclude Categories
          type: array
        exclude_path_prefixes:
          description: >-
            Files whose path starts with any of these are kept out of the graph
            corpus (override per file).
          items:
            maxLength: 1024
            type: string
          maxItems: 128
          title: Exclude Path Prefixes
          type: array
      title: KnowledgeGraphConfig
      type: object
    AccessConfig:
      additionalProperties: false
      description: >-
        A workspace's access-control setting, chosen once at creation.


        ``labels = []`` is the default and means **no filtering at all** — no

        classification pass at ingestion, no filter clause at retrieval, and

        ``Coverage`` reports nothing. A workspace that does not need
        document-level

        access control should not pay for a classification that always returns
        the

        same answer.


        Coverage reporting is always strict: whenever the gate withholds
        candidates,

        the response says so in counts and label names. A silently narrowed
        answer

        is the failure mode this platform exists to prevent, so there is no
        opt-out.
      properties:
        default_label:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            Applied when the classifier cannot decide. Required whenever labels
            is non-empty.
          title: Default Label
        labels:
          items:
            $ref: '#/components/schemas/AccessLabel'
          maxItems: 16
          title: Labels
          type: array
      title: AccessConfig
      type: object
    WorkspacePurpose:
      description: >-
        Why the platform provisioned a workspace nobody asked for.


        A purposed workspace is platform-managed: it is created on a person's

        behalf and it refuses deletion, so a caller can tell from a list
        response

        which row will answer 409 rather than discovering it by trying.
      enum:
        - perception_playground
      title: WorkspacePurpose
      type: string
    RetentionPolicy:
      additionalProperties: false
      description: >-
        A workspace's retention setting, chosen once at creation.


        ``derived_ttl_days`` anchors on ``ingested_at`` and ``source_ttl_days``
        on

        ``created_at`` — one anchor each, not configurable.
      properties:
        derived_ttl_days:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          description: >-
            Expire representations; source bytes untouched. The file moves to
            ingestion_status=expired.
          title: Derived Ttl Days
        job_ttl_days:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          default: 30
          description: >-
            How long job input and result payloads are retained. Null means kept
            forever.
          title: Job Ttl Days
        source_ttl_days:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          description: Delete source bytes from platform-managed storage.
          title: Source Ttl Days
      title: RetentionPolicy
      type: object
    WorkspaceStatus:
      description: >-
        Lifecycle states visible on the API surface.


        ``deleted`` is a final internal state; a deleted workspace never appears
        in

        any list or ``get`` response — it is as if it never existed.
      enum:
        - active
        - deleting
      title: WorkspaceStatus
      type: string
    Error:
      description: The error object, per spec 12 §1.8.
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        detail:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          description: Structured payload, when the code carries one.
          title: Detail
        message:
          description: Human- and model-readable; says what to do differently.
          title: Message
          type: string
        request_id:
          description: Per-request correlation id; matches the ``X-Request-Id`` header.
          title: Request Id
          type: string
        retryable:
          description: Whether retrying the identical request could succeed.
          title: Retryable
          type: boolean
      required:
        - code
        - message
        - retryable
        - request_id
      title: Error
      type: object
    AccessLabel:
      additionalProperties: false
      description: One label in a workspace's unordered list.
      properties:
        description:
          description: This string IS the classifier's prompt.
          title: Description
          type: string
        name:
          maxLength: 64
          pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
          title: Name
          type: string
      required:
        - name
        - description
      title: AccessLabel
      type: object
    ErrorCode:
      description: |-
        Every error the ``/v1`` surface can return.

        Clients must treat this as an **open** enum: a new member is an additive
        change (spec 12 §9), and a client that crashes on an unknown code makes
        every future error a breaking change.
      enum:
        - invalid_request
        - unsupported_file_type
        - file_too_large
        - invalid_schema
        - invalid_sql
        - invalid_path_prefix
        - command_not_permitted
        - batch_too_large
        - domain_validation_failed
        - default_label_required
        - wait_required_for_zero_retention
        - workspace_not_found
        - file_not_found
        - job_not_found
        - upload_not_found
        - node_not_found
        - schema_not_found
        - domain_not_found
        - session_not_found
        - access_label_not_found
        - path_conflict
        - schema_version_conflict
        - access_label_name_taken
        - workspace_name_taken
        - access_label_in_use
        - upload_expired
        - file_not_ingested
        - workspace_deleting
        - workspace_not_deletable
        - ingestion_in_progress
        - job_not_cancellable
        - confirmation_required
        - domain_not_published
        - domain_in_use
        - reserved_domain_slug
        - kg_not_built
        - kg_build_in_progress
        - session_busy
        - range_not_satisfiable
        - result_expired
        - access_denied
        - access_backstop_violation
        - access_mode_not_implemented
        - rate_limited
        - concurrency_limit_reached
        - quota_exceeded
        - corrupt_file
        - zero_byte_file
        - encrypted_file
        - parse_failed
        - ocr_failed
        - conversion_failed
        - sheetless_workbook
        - unplayable_media
        - unclassified_pages
        - job_cancelled
        - job_timeout
        - upstream_unavailable
        - internal_error
        - unauthorized
        - not_implemented
      title: ErrorCode
      type: string
  securitySchemes:
    APIKeyHeader:
      in: header
      name: X-API-Key
      type: apiKey

````