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
/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)
| Field | Type | Req | Description |
|---|---|---|---|
| id | string (UUID) | * | View identifier |
| surface | string | * | UI surface this view applies to |
| name | string | * | View display name |
| filters | JSON string | null | — | Serialized filter configuration |
| sorting | JSON string | null | — | Serialized sort configuration |
| columns | JSON string | null | — | Serialized column visibility/order |
| density | enum | * | comfortable, compact, or spacious |
| isDefault | boolean | * | Whether this is the default view for the surface |
| createdAt | ISO 8601 | * | Creation timestamp |
| updatedAt | ISO 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
/api/views Create a new saved view. If isDefault is true, any existing default for the same surface is automatically unset.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| surface | string | * | UI surface (e.g. tasks, documents, tables) |
| name | string | * | View display name |
| filters | object | — | Filter configuration (stored as JSON) |
| sorting | object | — | Sort configuration (stored as JSON) |
| columns | object | — | Column visibility and ordering (stored as JSON) |
| density | enum | — | comfortable (default), compact, or spacious |
| isDefault | boolean | — | Set 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
/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)
| Field | Type | Req | Description |
|---|---|---|---|
| name | string | — | Updated display name |
| filters | object | — | Updated filter configuration |
| sorting | object | — | Updated sort configuration |
| columns | object | — | Updated column visibility/order |
| density | enum | — | comfortable, compact, or spacious |
| isDefault | boolean | — | Set 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
/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
| Density | Description |
|---|---|
| comfortable | Default spacing. Good for scanning. |
| compact | Reduced padding. Shows more rows per screen. |
| spacious | Extra breathing room. Good for detailed review. |