---
title: "POST /workspace/{workspaceId}/views/{viewId}/validate"
method: POST
path: "/workspace/{workspaceId}/views/{viewId}/validate"
tags: ["Views"]
---

# POST /workspace/{workspaceId}/views/{viewId}/validate

`POST /workspace/{workspaceId}/views/{viewId}/validate`

## Request

- Base URL: `https://api.craft.io`
- URL: `https://api.craft.io/workspace/{workspaceId}/views/{viewId}/validate`
- Auth: API key in header `x-api-key`

Check a change to a view without making it — see validateWorkspaceViewCreate.

## Path parameters

- `workspaceId` string, required
- `viewId` string, required

## Request body

- ViewUpdateBody
  - `name` string
  - `category` string
  - `filters` ViewFiltersInput: A view's filters, in the same vocabulary the item list endpoints use — so a filter you can pass to list_items works here unchanged, and vice versa. Every list takes ids OR names (names are resolved, and an unknown one is a 422 naming the valid values). An empty list clears that filter. `"-1"` means "items with no value set", the same sentinel the app uses. Portfolio views: `assignee` does not apply, and quarter / sprint / importance are matched by name because a portfolio merges them across its workspaces.
    - `type` string[]: Item types — the view's hierarchy control. e.g. `epic`, `feature`, `story`.
    - `status` string[]
    - `importance` string[]
    - `quarter` string[]: Release / quarter.
    - `sprint` string[]
    - `assignee` string[]: Workspace views only.
    - `labels` string[]
    - `createdBy` string[]
    - `epic` string[]: Ancestor epic ids.
    - `product` string[]: Product / theme names or ids — the Product an item sits under. Not the same as `workspace`.
    - `workspace` string[]: Source workspace ids — which workspace a row came from. Portfolio views only.
    - `initiative` string[]: Linked portfolio initiative ids.
    - `objectives` string[]
    - `keyResults` string[]
    - `persona` string[]
    - `statusCategory` string[]: Workflow bucket: `open`, `inProgress`, `done`.
    - `dependencies` string[]: Dependency Proximity: `none`, `related`, `blockedBy`, `blocks`.
    - `startDate` ViewDateRange
      - `from` string: ISO 8601 date.
      - `to` string: ISO 8601 date.
    - `endDate` ViewDateRange
      - `from` string: ISO 8601 date.
      - `to` string: ISO 8601 date.
    - `customFields` ViewCustomFieldFilter[]
      - `id` string, required: Field id from get_workspace_custom_fields / get_portfolio_fields.
      - `values` string[], required: Option ids or labels.
  - `replaceAllFilters` boolean
  - `controllers` ViewControllersInput
    - `sortBy` string: Sort axis, e.g. `status`, `importance`, `hierarchy`, `custom:<fieldId>`.
    - `sortDirection` 'asc' | 'desc'
    - `groupBy` string: Grouping axis. Not available on timeline views. `none` clears it.
    - `swimLanesBy` string: Swim-lane axis. Timeline and swimlanes views only. `none` clears it — the app's "None".
  - `columns` string[]: Ordered visible columns — table and okr-table only. Replaces the current set outright; there is no per-column merge. Supported because the app changes columns on an existing view through the same call. Without it an agent asked to add one column had to recreate the whole view, which left the original behind as a duplicate.
  - `layout` string[]: Card fields — kanban, timeline and swimlanes only. Replaces the current set.
  - `columnColors` object: Per-column colours as `#RRGGBB`, keyed like `columns`. Send `{}` to clear. Duplicating a view: pass what get_view returned, or the copy loses them.
  - `compactMode` string: Card density, kanban / timeline / swimlanes only: `compact` or `default`.

## Response `200`

The view as it would be after the change

- ViewDetail
  - `viewId` string, required
  - `name` string, required
  - `viewType` string, required
  - `ownerType` 'personal' | 'workspace', required
  - `category` string
  - `workspaceId` string
  - `portfolioId` string
  - `webUrl` string
  - `controllers` ViewControllers, required
    - `sortBy` string
    - `sortDirection` 'asc' | 'desc'
    - `groupBy` string
    - `swimLanesBy` string
    - `sortByName` string: Display names for whichever of the axes above is a custom field. Every other axis already comes back as a name — "status", "importance" — and only a custom field is returned as `custom:<id>`, because that id is also what the write path takes. So a reader had an opaque number and no way to say what the view was grouped by without a second call, and an assistant describing a view printed the id at the user. Added alongside rather than replacing the value: `custom:<id>` is the input format axisToWire parses, and external clients read a view and write it back. Changing it would break them.
    - `groupByName` string
    - `swimLanesByName` string
  - `columns` string[]
  - `layout` string[]
  - `compactMode` string: Card density on a card-based view: `compact` or `default`.
  - `filters` RecordStringUnknown, required: Construct a type with a set of properties K of type T
  - `listItemsParams` RecordStringString, required: Construct a type with a set of properties K of type T
  - `listItemsTool` 'list_items' | 'list_portfolio_items' | 'list_feedback_items', required: Which list tool `listItemsParams` belongs to. Feedback views are the reason this is stated rather than assumed — their items are not work items.
  - `unsupportedFilters` UnsupportedFilter[]: Filters the list endpoints cannot reproduce — the result will be wider.
    - `filter` string, required
    - `reason` string, required
  - `inactiveControllers` InactiveController[]: Axes the view stores but the app does not apply, so they are left out of `controllers` — which then reads the way the app shows the view.
    - `controller` 'groupBy' | 'swimLanesBy', required
    - `storedValue` string, required
    - `reason` string, required
  - `columnColors` RecordStringString: Construct a type with a set of properties K of type T
  - `raw` WireView: A view exactly as the views service stores it. Unknown props round-trip.
    - `id` string
    - `name` string
    - `categoryId` string
    - `workspaceId` string
    - `personId` string, nullable
    - `ownerType` string
    - `viewType` string
    - `orderIndex` string
    - `category` string, nullable
    - `nameId` string, nullable
    - `description` string, nullable
    - `viewFields` string[], nullable
    - `compactViewFields` string[], nullable
    - `compactMode` string, nullable: Card density on a card-based view; empty string means never set.
    - `groupBy` string, nullable
    - `groupByCustomFieldId` string, nullable
    - `secondaryGroupBy` string, nullable
    - `secondaryGroupByCustomFieldId` string, nullable
    - `sortBy` string, nullable
    - `sortByCustomFieldId` string, nullable
    - `reverse` boolean, nullable
    - `isChanged` boolean
    - `okrHierarchy` string, nullable
    - `fieldFilters` RecordStringUnknown: Construct a type with a set of properties K of type T
    - `filters` RecordStringUnknown: Construct a type with a set of properties K of type T

## Other responses

- `403`: Access denied
- `404`: No view found
- `422`: The update would be refused

## Changes

- **2026-11-02** `2972a1b05ab1`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/craft/apis/craft-io-public-api/changes/workspace/:workspaceId/views/:viewId/validate/post.md)

---

[API](https://skmtc.dev/craft/apis/craft-io-public-api.md) - [All operations](https://skmtc.dev/craft/apis/craft-io-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/craft/apis/craft-io-public-api/revisions/2972a1b05ab1?raw)
