Views API

Views let users save and recall custom filter, sort, column, and density configurations for any list surface in the UI. Each view is scoped to a surface (e.g. tasks, documents, tables) and one view per surface can be marked as the default.

Quick Start

Create a saved view with filters, apply it as the default, then update it later:

// 1. Create a saved view for the tasks surface
const view: { id: string; surface: string; name: string; isDefault: boolean } =
await fetch('/api/views', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    surface: 'tasks',
    name: 'High Priority Active',
    filters: { priority: [0, 1], status: ['running', 'queued'] },
    sorting: { column: 'priority', direction: 'asc' },
    columns: { visible: ['title', 'status', 'priority', 'assignedAgent'], order: ['priority', 'title', 'status', 'assignedAgent'] },
    density: 'compact',
    isDefault: true,
  }),
}).then((r) => r.json());
// → { id: "view-4a2b-8c9d", surface: "tasks", name: "High Priority Active", isDefault: true }

// 2. List all views for the tasks surface
const views: Array<{ name: string; isDefault: boolean }> =
await fetch('/api/views?surface=tasks').then((r) => r.json());
// Default view is always first in the list
console.log(`${views.length} saved views, default: ${views[0].name}`);

// 3. Update the view — add a new filter without changing the rest
await fetch(`/api/views/${view.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
  filters: { priority: [0, 1], status: ['running', 'queued'], assignedAgent: 'claude-code' },
}),
});

// 4. Delete a view when no longer needed
await fetch(`/api/views/${view.id}`, { method: 'DELETE' });

Base URL

/api/views

Endpoints

List Views

GET /api/views

List all saved views for a given surface. Results are ordered with the default view first, then alphabetically by name.

Query Parameters

Param Type Req Description
surface string Required. The UI surface to list views for (e.g. tasks, documents, tables)

Response Body (Array)

FieldTypeReqDescription
idstring (UUID)*View identifier
surfacestring*UI surface this view applies to
namestring*View display name
filtersJSON string | nullSerialized filter configuration
sortingJSON string | nullSerialized sort configuration
columnsJSON string | nullSerialized column visibility/order
densityenum*comfortable, compact, or spacious
isDefaultboolean*Whether this is the default view for the surface
createdAtISO 8601*Creation timestamp
updatedAtISO 8601*Last modification

Errors: 400 — Missing surface parameter

Fetch all saved views for a surface — the default view is always listed first:

// List views and find the default
const views: Array<{ name: string; isDefault: boolean; density: string }> =
await fetch('/api/views?surface=tasks').then((r) => r.json());

const defaultView = views.find((v) => v.isDefault);
if (defaultView) {
console.log(`Default view: ${defaultView.name} (${defaultView.density})`);
}
views.forEach((v) => console.log(`  ${v.isDefault ? '*' : ' '} ${v.name}`));

Example response:

[
  {
    "id": "view-4a2b-8c9d",
    "surface": "tasks",
    "name": "High Priority Active",
    "filters": "{\"priority\":[0,1],\"status\":[\"running\",\"queued\"]}",
    "sorting": "{\"column\":\"priority\",\"direction\":\"asc\"}",
    "columns": "{\"visible\":[\"title\",\"status\",\"priority\",\"assignedAgent\"]}",
    "density": "compact",
    "isDefault": true,
    "createdAt": "2026-04-03T10:00:00.000Z",
    "updatedAt": "2026-04-03T10:00:00.000Z"
  },
  {
    "id": "view-5b3c-9d0e",
    "surface": "tasks",
    "name": "All Tasks",
    "filters": null,
    "sorting": null,
    "columns": null,
    "density": "comfortable",
    "isDefault": false,
    "createdAt": "2026-04-02T08:00:00.000Z",
    "updatedAt": "2026-04-02T08:00:00.000Z"
  }
]

Create View

POST /api/views

Create a new saved view. If isDefault is true, any existing default for the same surface is automatically unset.

Request Body

FieldTypeReqDescription
surfacestring*UI surface (e.g. tasks, documents, tables)
namestring*View display name
filtersobjectFilter configuration (stored as JSON)
sortingobjectSort configuration (stored as JSON)
columnsobjectColumn visibility and ordering (stored as JSON)
densityenumcomfortable (default), compact, or spacious
isDefaultbooleanSet as default view for this surface

Response 201 Created — New view object

Create a compact view showing only high-priority active tasks — setting it as the default automatically clears any previous default:

// Create a default view for the tasks surface
const view: { id: string; isDefault: boolean } = await fetch('/api/views', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
  surface: 'tasks',
  name: 'High Priority Active',
  filters: { priority: [0, 1], status: ['running', 'queued'] },
  sorting: { column: 'priority', direction: 'asc' },
  columns: { visible: ['title', 'status', 'priority', 'assignedAgent'] },
  density: 'compact',
  isDefault: true,
}),
}).then((r) => r.json());

console.log(`Created view: ${view.id} (default: ${view.isDefault})`);

Example response:

{
  "id": "view-4a2b-8c9d",
  "surface": "tasks",
  "name": "High Priority Active",
  "filters": "{\"priority\":[0,1],\"status\":[\"running\",\"queued\"]}",
  "sorting": "{\"column\":\"priority\",\"direction\":\"asc\"}",
  "columns": "{\"visible\":[\"title\",\"status\",\"priority\",\"assignedAgent\"]}",
  "density": "compact",
  "isDefault": true,
  "createdAt": "2026-04-03T10:00:00.000Z",
  "updatedAt": "2026-04-03T10:00:00.000Z"
}

Errors: 400 — Missing surface or name

Update View

PATCH /api/views/{id}

Update a saved view. If isDefault is set to true, any existing default for the same surface is automatically cleared.

Request Body (all fields optional)

FieldTypeReqDescription
namestringUpdated display name
filtersobjectUpdated filter configuration
sortingobjectUpdated sort configuration
columnsobjectUpdated column visibility/order
densityenumcomfortable, compact, or spacious
isDefaultbooleanSet or unset as default

Response 200 — Updated view object

Update a view’s density and rename it — useful when refining saved views over time:

// Refine an existing view
await fetch('/api/views/view-4a2b-8c9d', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
  name: 'Critical Tasks Only',
  filters: { priority: [0], status: ['running', 'queued'] },
  density: 'spacious',
}),
});

Errors: 404 — View not found

Delete View

DELETE /api/views/{id}

Permanently delete a saved view.

Response 200{ "ok": true }

// Delete a view that is no longer needed
await fetch('/api/views/view-4a2b-8c9d', { method: 'DELETE' });

Errors: 404 — View not found

View Density Options

DensityDescription
comfortableDefault spacing. Good for scanning.
compactReduced padding. Shows more rows per screen.
spaciousExtra breathing room. Good for detailed review.