# Create (or `replace`) a view: a named select stored in metastore.yaml. Name it with the prefix

`POST /datanotes/operations/create_view/` (operation `create_view`)

Create (or `replace`) a view: a named select stored in metastore.yaml. Name it with the prefix
`vw_` (e.g. `vw_open_tasks`): views share names and folders with tables. `query` takes the
select_rows parameters (table, columns, where, order_by, limit, join, group_by, aggregates, expand;
relative dates keep it current) and must run now. Or `query: {union: [{table, columns, where}, …],
columns, where, order_by, limit, expand}` stacks the rows of several tables (UNION ALL, each row
tagged `_source`). Its filters may read the note the view is shown for: `{this.<property>}`
(`{this.date+1d}`, `{this.date-1w}` shift a date), `{this.link}`, `{this.name}`, `{this.path}`,
filled in from select_rows `this_note` (one view serves every daily note, every project note).
`description` and `aliases` let agents find it; `labels` are column headings. Views are selected with
`select_rows(table=<view>)`, which may narrow them further (where, columns, order_by, limit; a `where`
operator the view already has on a column replaces it). A view writes no note: it lives only in
metastore.yaml.

The schema changes only through operations like this one: never edit metastore.yaml by hand (no validation, no undo).

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `X-Datanotes-Actor` | header | `string` | no | JSON: on whose behalf the write is made, recorded in the journal (`harness`, `model`, `session`). |

## Request body

`application/json`, required

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `name` | `string` | yes |  |  |
| `query` | `object` | yes |  |  |
| `catalog` | `string \| null` | no | `null` |  |
| `schema` | `string \| null` | no | `null` |  |
| `description` | `string \| null` | no | `null` | What the view shows, for agents and people. |
| `aliases` | `string[] \| null` | no | `null` |  |
| `labels` | `object \| null` | no | `null` |  |
| `replace` | `boolean` | no | `false` |  |
| `dry_run` | `boolean` | no | `false` |  |

## Responses

| Status | Description | Body |
| --- | --- | --- |
| 200 | Done. | `OpResult` (application/json) |
| 400 | Bad input: the body is not a JSON object, or an argument is unknown, missing or of the wrong type. | `Error` (application/json) |
| 401 | Missing or wrong bearer token. | `Error` (application/json) |
| 403 | A named token beyond its permissions (the engine's administration, tables outside its `write` patterns, schema changes without `ddl`). | `Error` (application/json) |
| 422 | Refused (validation failures, conflicts, an unmet `expect`): nothing written. Same body as 200, with `ok: false` and the reasons. | `OpResult` (application/json) |
| 500 | Unexpected error (`{error}`), or a write that failed partway and could not be rolled back: `rolled_back: false`, `failed` lists the files left (undo_migration on `migration_id` retries the rollback). | `OpResult \| Error` (application/json) |
| 503 | A write that failed partway (a file another program holds) and was rolled back: `rolled_back: true`, nothing written. Send it again later. Same body as 200, with `ok: false` and `failed`. | `OpResult` (application/json) |

The schemas named here are in [openapi.json](https://datanotes.dev/openapi.json) (`components.schemas`).
