---
title: "update_workspace"
method: PATCH
path: "/v1/workspaces/{workspace_id}"
tags: ["workspaces"]
---

# update_workspace

`PATCH /v1/workspaces/{workspace_id}`

## Request

- Base URL: `https://ndi-api.nace.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://ndi-api.nace.ai/v1/workspaces/{workspace_id}`
- Auth: API key in header `X-API-Key`
- TypeScript: <https://skmtc.dev/nace/apis/ndi-service/docs/v1/workspaces/:workspace_id/patch.ts> (a function with typed inputs; its response is checked against the schema)

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.

Ordinary workspace names are mutable without changing identity or storage;
platform-provisioned workspace names remain fixed.
The domain and label list are deliberately not mutable here. They 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.

Args:
    context: Resolved workspace plus the caller's access predicate.
    session: Database session.
    request: The name and/or blocks to replace.

Returns:
    The workspace as it now stands.

Raises:
    PlatformError: ``workspace_not_found``, ``workspace_deleting`` when a
        teardown is in flight; ``workspace_name_taken`` for an occupied name,
        ``invalid_request`` for a system-workspace rename, ``access_denied``
        when a shared member attempts a rename.

## Path parameters

- `workspace_id` string, uuid, required: Workspace identifier.

## Request body

- UpdateWorkspaceRequest: 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. The display name of an ordinary workspace (platform-provisioned names stay fixed), the knowledge-graph, currency and ledger-understanding policies and the global context are mutable. 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.
  - `name` string: New display name for an ordinary workspace. Platform-provisioned names are fixed. Omit to keep the current name; null is not accepted.
  - `knowledge_graph` KnowledgeGraphConfig: A workspace's knowledge-graph build policy. The defaults keep the whole corpus in scope and build the graph after every ingestion, so fact search and deep search have it to navigate by. Set ``auto_build=false`` for a workspace that builds only on request. ``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.
    - `auto_build` boolean: Build the graph automatically after each ingestion completes. On by default; turn it off to build only on request (a build is billable and long-running). Ingestion skips the automatic build once the graph corpus reaches the deployment's kg.auto_build.max_corpus_files limit; an explicit build still runs.
    - `exclude_path_prefixes` string[]: Files whose path starts with any of these are kept out of the graph corpus (override per file).
    - `exclude_categories` string[]: Files whose category is any of these are kept out of the graph corpus (override per file).
  - `currency` CurrencyPolicy: 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.
    - `default` string, nullable: ISO 4217 code, e.g. 'USD'.
  - `ledger_understanding` LedgerUnderstandingConfig: A workspace's ledger-understanding policy. On by default in its cheapest form: ``auto`` costs a workspace with no ledger in it nothing at all, because the test for "is there a ledger here" is the census's own pure predicate over sidecars that ingestion already wrote.
    - `engine` 'measured' | 'llm': Discovery method; selected packages always run measured validation.
    - `package_confirmation` 'required' | 'automatic': Who confirms an llm-discovered package before GL parsing: a person, or the model on its own. When a person must, parsing runs only on the mapping that person confirmed.
    - `package_scope` LedgerPackageScope: A package's source files: every file under the prefix plus every explicit path.
      - `path_prefix` string, nullable: Folder containing the package, relative to the workspace root.
      - `paths` string[]: Exact source paths in the package, added to every path under the prefix.
      - `selection_id` string, uuid, nullable: Protected, immutable source-role selection reference.
    - `trigger` 'auto' | 'always' | 'off': When an ingestion should chain the stage: only for a workspace that holds a journal-line table, after every ingestion that landed files, or never.
    - `gl_parsing` boolean: Whether the stage should also map each journal's account/debit-credit groups to balanced sub-journals and publish the mapping as a derived table.
    - `prepared_relationships` PreparedRelationshipConfig[]: Reviewed large-table relationships to prepare before JET starts. Empty disables preparation.
      - `name` string, required: Stable name for the prepared relationship.
      - `left` PreparedTableSelectionConfig, required: One logical source table selected by its stable workspace coordinate.
        - `path` string, required: Workspace path or published dataset root.
        - `component` string, nullable: Worksheet or component when the path has more than one table.
      - `right` PreparedTableSelectionConfig, required: One logical source table selected by its stable workspace coordinate.
        - `path` string, required: Workspace path or published dataset root.
        - `component` string, nullable: Worksheet or component when the path has more than one table.
      - `keys` PreparedKeyConfig[], required: Ordered equality key components.
        - `left_column` string, required: Column on the left table.
        - `right_column` string, required: Column on the right table.
        - `left_normalization` union: Reviewed normalization applied to the left column.
          - PreparedIdentityNormalizationConfig: Compare a VARCHAR key exactly as stored.
            - `kind` 'identity': Keep the stored text unchanged.
          - PreparedLeftPadNormalizationConfig: Apply the declared single-character left padding before comparison.
            - `kind` 'left_pad': Left-pad the stored text to a fixed width.
            - `width` integer, required: Width of the normalized key.
            - `fill` string, required: Single character used for padding.
        - `right_normalization` union: Reviewed normalization applied to the right column.
          - PreparedIdentityNormalizationConfig: Compare a VARCHAR key exactly as stored.
            - `kind` 'identity': Keep the stored text unchanged.
          - PreparedLeftPadNormalizationConfig: Apply the declared single-character left padding before comparison.
            - `kind` 'left_pad': Left-pad the stored text to a fixed width.
            - `width` integer, required: Width of the normalized key.
            - `fill` string, required: Single character used for padding.
      - `bucket_count` integer, required: Number of hash buckets materialized on each side.
  - `global_context` string, nullable: The workspace's new global context, or omitted to leave it unchanged; `""` clears it. Standing background for every query in this workspace — how its journals are keyed, which entity it covers, what an auditor already knows. A je-testing or search request that omits `context` runs with this text; a request that sends `context` replaces it for that run, and `""` runs with none. Empty means none. Surrounding whitespace is stripped.

## Response `200`

Successful Response

- Workspace: A provisioned workspace, as the API returns it. Storage metadata identifies the durable backend without exposing credentials.
  - `storage` union: The workspace's durable storage backend and external connection health.
    - ManagedWorkspaceStorage
      - `type` 'managed'
    - TenantBucketWorkspaceStorage
      - `type` 'tenant_bucket'
      - `provider` 's3'
      - `location` string, required: Workspace namespace in the tenant's configured bucket.
    - ExternalWorkspaceStorage
      - `type` 'external'
      - `connection_id` string, uuid, nullable: Reusable storage connection bound permanently to this workspace; each workspace has its own exclusive namespace. Null when the caller cannot view the storage connection.
      - `provider` 's3' | 'azure_blob', nullable: Customer object storage provider. Null when the caller cannot view the storage connection.
      - `location` string, nullable: Exclusive namespace containing this workspace's durable objects. Null when the caller cannot view the storage connection.
      - `health` 'draft' | 'ready' | 'degraded' | 'revoked', nullable: Current connection authorization state. Null when the caller cannot view the storage connection.
  - `workspace_id` string, uuid, required
  - `owner_user_id` string, uuid, nullable, required: The console user who owns the workspace, or null for an organization-owned integration workspace.
  - `share_count` integer, required: Number of users explicitly granted workspace access; excludes the owner.
  - `name` string, required
  - `domain_id` string, uuid, required
  - `domain_slug` string, required
  - `domain_version` integer, required
  - `access` AccessConfig, required: 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.
    - `labels` AccessLabel[]
      - `name` string, required
      - `description` string, required: This string IS the classifier's prompt.
    - `default_label` string, nullable: Applied when the classifier cannot decide. Required whenever labels is non-empty.
  - `knowledge_graph` KnowledgeGraphConfig, required: A workspace's knowledge-graph build policy. The defaults keep the whole corpus in scope and build the graph after every ingestion, so fact search and deep search have it to navigate by. Set ``auto_build=false`` for a workspace that builds only on request. ``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.
    - `auto_build` boolean: Build the graph automatically after each ingestion completes. On by default; turn it off to build only on request (a build is billable and long-running). Ingestion skips the automatic build once the graph corpus reaches the deployment's kg.auto_build.max_corpus_files limit; an explicit build still runs.
    - `exclude_path_prefixes` string[]: Files whose path starts with any of these are kept out of the graph corpus (override per file).
    - `exclude_categories` string[]: Files whose category is any of these are kept out of the graph corpus (override per file).
  - `currency` CurrencyPolicy, required: 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.
    - `default` string, nullable: ISO 4217 code, e.g. 'USD'.
  - `ledger_understanding` LedgerUnderstandingConfig: A workspace's ledger-understanding policy. On by default in its cheapest form: ``auto`` costs a workspace with no ledger in it nothing at all, because the test for "is there a ledger here" is the census's own pure predicate over sidecars that ingestion already wrote.
    - `engine` 'measured' | 'llm': Discovery method; selected packages always run measured validation.
    - `package_confirmation` 'required' | 'automatic': Who confirms an llm-discovered package before GL parsing: a person, or the model on its own. When a person must, parsing runs only on the mapping that person confirmed.
    - `package_scope` LedgerPackageScope: A package's source files: every file under the prefix plus every explicit path.
      - `path_prefix` string, nullable: Folder containing the package, relative to the workspace root.
      - `paths` string[]: Exact source paths in the package, added to every path under the prefix.
      - `selection_id` string, uuid, nullable: Protected, immutable source-role selection reference.
    - `trigger` 'auto' | 'always' | 'off': When an ingestion should chain the stage: only for a workspace that holds a journal-line table, after every ingestion that landed files, or never.
    - `gl_parsing` boolean: Whether the stage should also map each journal's account/debit-credit groups to balanced sub-journals and publish the mapping as a derived table.
    - `prepared_relationships` PreparedRelationshipConfig[]: Reviewed large-table relationships to prepare before JET starts. Empty disables preparation.
      - `name` string, required: Stable name for the prepared relationship.
      - `left` PreparedTableSelectionConfig, required: One logical source table selected by its stable workspace coordinate.
        - `path` string, required: Workspace path or published dataset root.
        - `component` string, nullable: Worksheet or component when the path has more than one table.
      - `right` PreparedTableSelectionConfig, required: One logical source table selected by its stable workspace coordinate.
        - `path` string, required: Workspace path or published dataset root.
        - `component` string, nullable: Worksheet or component when the path has more than one table.
      - `keys` PreparedKeyConfig[], required: Ordered equality key components.
        - `left_column` string, required: Column on the left table.
        - `right_column` string, required: Column on the right table.
        - `left_normalization` union: Reviewed normalization applied to the left column.
          - PreparedIdentityNormalizationConfig: Compare a VARCHAR key exactly as stored.
            - `kind` 'identity': Keep the stored text unchanged.
          - PreparedLeftPadNormalizationConfig: Apply the declared single-character left padding before comparison.
            - `kind` 'left_pad': Left-pad the stored text to a fixed width.
            - `width` integer, required: Width of the normalized key.
            - `fill` string, required: Single character used for padding.
        - `right_normalization` union: Reviewed normalization applied to the right column.
          - PreparedIdentityNormalizationConfig: Compare a VARCHAR key exactly as stored.
            - `kind` 'identity': Keep the stored text unchanged.
          - PreparedLeftPadNormalizationConfig: Apply the declared single-character left padding before comparison.
            - `kind` 'left_pad': Left-pad the stored text to a fixed width.
            - `width` integer, required: Width of the normalized key.
            - `fill` string, required: Single character used for padding.
      - `bucket_count` integer, required: Number of hash buckets materialized on each side.
  - `global_context` string: Standing background for every query in this workspace — how its journals are keyed, which entity it covers, what an auditor already knows. A je-testing or search request that omits `context` runs with this text; a request that sends `context` replaces it for that run, and `""` runs with none. Empty means none. Surrounding whitespace is stripped.
  - `config_version` integer, required
  - `status` 'active' | 'deleting', required: 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.
  - `purpose` 'perception_playground': 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.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `402`: Payment Required
- `403`: Forbidden
- `404`: Not Found
- `409`: Conflict
- `410`: Gone
- `413`: Request Entity Too Large
- `422`: Unprocessable Entity
- `424`: Failed Dependency
- `429`: Too Many Requests
- `500`: Internal Server Error
- `501`: Not Implemented
- `503`: Service Unavailable
- `504`: Gateway Timeout

---

[API](https://skmtc.dev/nace/apis/ndi-service.md) - [All operations](https://skmtc.dev/nace/apis/ndi-service/llms.txt) - [OpenAPI document](https://skmtc.dev/nace/apis/ndi-service/revisions/d9d1f8ec2207?raw)
