# Lydie Developers

> Lydie is a writing app for notes and documents in plain Markdown, alone or with a team. Its REST API and MCP server let scripts and AI agents read, write and organise the pages of a hosted workspace.

Notes for agents:

- REST base URL: https://api.lydie.co/v1. MCP server (Streamable HTTP): https://api.lydie.co/mcp. Prefer MCP when you are an AI assistant.
- Authenticate with `Authorization: Bearer <token>`: a personal API token (`lyd_pat_…`) or an OAuth access token. A token belongs to one workspace and has the scopes `docs:read` and/or `docs:write`.
- Document bodies are Markdown (CommonMark + GFM + wikilinks). To edit, prefer `edits` (exact oldStr/newStr replacements) over replacing the whole body, and pass `expectedVersion` from the last read.
- Your changes are recorded as an agent acting for the token's owner. MCP changes form one session that `undo_session` reverts.
- The OpenAPI document at https://developers.lydie.co/openapi.json is the source of truth for every field.

---

# Quickstart

Source: https://developers.lydie.co/quickstart

> Create an API token, find your workspace, and create, read and edit a document with the REST API.

This takes about five minutes with `curl`. You need a Lydie account and a workspace.

## 1. Create an API token

In Lydie, open **Settings → Agents & API**. Under **Hosted API**, give a token a name and create
it. Copy the secret, which starts with `lyd_pat_`. Lydie shows it once.

```bash
export LYDIE_TOKEN="lyd_pat_..."
```

A token belongs to one workspace and acts as you. [Authentication](https://developers.lydie.co/authentication.md) explains what it
can and cannot do.

## 2. Find your workspace

```bash
curl https://api.lydie.co/v1/workspaces \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

A token sees only its own workspace, so the list has one entry:

```json
{
  "workspaces": [
    {
      "id": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "name": "Notes",
      "role": "owner",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

```bash
export WORKSPACE="01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
```

## 3. Create a document

```bash
curl -X POST https://api.lydie.co/v1/documents \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "'"$WORKSPACE"'",
    "title": "Meeting notes",
    "markdown": "# Meeting notes\n\n- Ship the developer docs"
  }'
```

The response is the new [document](https://developers.lydie.co/api/documents.md). A top-level page goes to your private section
unless you pass a `teamspaceId`. Keep its `id`:

```bash
export DOC="01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
```

## 4. Read it

```bash
curl https://api.lydie.co/v1/documents/$DOC \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

```json
{
  "document": { "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB", "title": "Meeting notes", "...": "..." },
  "body": {
    "markdown": "# Meeting notes\n\n- Ship the developer docs",
    "version": "c2f1…"
  }
}
```

## 5. Edit it

Send exact replacements instead of the whole body. Include the `version` you read, so the edit
fails with `409 conflict` if someone changed the page in the meantime:

```bash
curl -X PATCH https://api.lydie.co/v1/documents/$DOC/body \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "edits": [{ "oldStr": "Ship the developer docs", "newStr": "Shipped the developer docs" }],
    "expectedVersion": "c2f1…"
  }'
```

If someone has the page open, they see the change appear. An edit that does not match exactly once
is skipped and listed in `warnings`.

## Next

- Connect an AI assistant instead: [MCP server](https://developers.lydie.co/mcp.md).
- How bodies, properties and links work: [Documents and Markdown](https://developers.lydie.co/documents.md).
- Every endpoint: [API reference](https://developers.lydie.co/api.md).

---

# Authentication

Source: https://developers.lydie.co/authentication

> Personal API tokens for scripts, OAuth 2.1 for apps and MCP clients, and what each kind of token may do.

Every request sends a bearer token:

```http
Authorization: Bearer lyd_pat_...
```

Tokens work on the operation routes under `https://api.lydie.co/v1` and on the MCP server at
`https://api.lydie.co/mcp`. Everything else answers `401`.

## Personal API tokens

Use one for your own scripts and agents. Create it in **Settings → Agents & API → Hosted API**, or
with [Create an API token](https://developers.lydie.co/api/api-tokens/create-an-api-token.md) from a signed-in session.

- The secret is `lyd_pat_` followed by 43 characters. Lydie shows it once and stores only a hash.
- **Scopes:** `docs:read` lets the token read, and `docs:write` lets it make changes. New tokens get
  both unless you choose read only.
- **Expiry:** never, or after a number of days you choose.
- **Revoke** it in the same settings page. It stops working at once.

## What a token can do

A token acts as you, with your access to pages, and is limited to the workspace it was made for.

- Pages, teamspaces and members of other workspaces answer `404 not_found`, as if they did not exist.
- An operation needs the token's scope: queries need `docs:read` and changes need `docs:write`. A
  token without the scope gets `403 forbidden`.
- Some operations need a signed-in session in the Lydie app and refuse every token with `403`.
  These include managing tokens and connected apps, creating a workspace, transferring ownership,
  leaving a workspace, and accepting or declining invitations. The reference marks them.

Changes made with a token are recorded as an agent acting for you. The document's `createdBy` or
`updatedBy` reads `agent:api-token:<token id>:<your user id>`. See
[Agent changes and undo](https://developers.lydie.co/agent-history.md).

## OAuth 2.1

OAuth is for apps that act for other people, and for MCP clients. The person approves the app in
Lydie, picks a workspace, and can narrow the scopes. MCP clients that support the MCP authorization
spec do all of this themselves: give them `https://api.lydie.co/mcp` and they open the sign-in page.

| Step                 | Endpoint                                                                                       |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| Discovery            | `GET /.well-known/oauth-protected-resource/mcp`, `GET /.well-known/oauth-authorization-server` |
| Register the client  | `POST /oauth/register` (RFC 7591, public clients), or a client ID metadata document URL        |
| Authorize            | `GET /oauth/authorize` with `response_type=code`, PKCE `S256` (required), `state`, `scope`     |
| Exchange and refresh | `POST /oauth/token` (`authorization_code`, `refresh_token`)                                    |
| Revoke               | `POST /oauth/revoke` (RFC 7009)                                                                |

All endpoints are on `https://api.lydie.co`. A request to `/mcp` without a token gets `401` with a
`WWW-Authenticate` header pointing at the discovery document.

- Scopes are the same as for API tokens: `docs:read docs:write`.
- Access tokens (`lyd_oat_…`) last one hour and have the same limits as API tokens.
- Refresh tokens (`lyd_ort_…`) last 30 days and rotate on every use. Reusing an old refresh token
  revokes the whole grant.
- Redirect URIs must be `https`, `http` on a loopback address (any port), or an app's own scheme.
- People see and disconnect apps under **Settings → Agents & API → Connected apps**.

---

# MCP server

Source: https://developers.lydie.co/mcp

> Connect Claude, Cursor, VS Code or any MCP client to a Lydie workspace, hosted or on your own computer.

Lydie's MCP server lets AI assistants search, read and edit your pages. It uses the same operations
as the REST API, so an agent can do what you can do in the app.

```text
https://api.lydie.co/mcp
```

It speaks Streamable HTTP and answers each request with JSON. It keeps no state between requests.

## Connect a client

Most clients sign in with OAuth: they open Lydie, you pick a workspace and approve. To use an
[API token](https://developers.lydie.co/authentication.md) instead, add an `Authorization: Bearer lyd_pat_…` header to the
configs below. **Settings → Agents & API → Hosted MCP** in the app shows these snippets with your
token filled in.

### Claude Code

```bash
claude mcp add --transport http lydie https://api.lydie.co/mcp
```

### Cursor

```json title=".cursor/mcp.json"
{
  "mcpServers": {
    "lydie": { "url": "https://api.lydie.co/mcp" }
  }
}
```

### VS Code

```json title=".vscode/mcp.json"
{
  "servers": {
    "lydie": { "type": "http", "url": "https://api.lydie.co/mcp" }
  }
}
```

### Claude Desktop

```json title="claude_desktop_config.json"
{
  "mcpServers": {
    "lydie": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.lydie.co/mcp"]
    }
  }
}
```

## Tools

The server lists a small set of agent-sized tools: `search`, `list_docs`, `fetch_doc`,
`create_doc`, `update_doc`, the database tools such as `query_database` and `write_database_rows`,
and the history tools. [MCP tools](https://developers.lydie.co/mcp/tools.md) lists them all with their inputs.

Two more tools reach everything else. `describe_operation` returns an operation's input and output
schema, and `run_operation` runs it by id. These cover teamspaces, sharing, publishing,
notifications and the fine-grained database operations.

Good habits for agents:

- Find pages with `search` or `list_docs`, then read them with `fetch_doc`.
- Change a body with `update_doc` and `edits` (exact `oldStr`/`newStr` pairs), not by sending the
  whole page. Pass the `expectedVersion` from `fetch_doc`.
- Read `warnings` in the result: an edit that did not match exactly once was skipped.

## Undo what an agent did

Each connection is one history session. `list_session_changes` shows what the agent changed, and
`undo_session` reverts all of it in one step. See [Agent changes and undo](https://developers.lydie.co/agent-history.md).

## On your own computer

The desktop app can run a local MCP server for a workspace opened from a folder. No account or
network is needed, and every change is written to the Markdown files in that folder. Turn it on
under **Settings → Agents & API → On this computer**. It listens on `127.0.0.1` and needs the token
from the token file shown there.

The tools are the same as on the hosted server. The `lydie` command-line tool in the
[open-source client](https://github.com/lydiehq/lydie/tree/v2/packages/cli) runs the same server
with `lydie mcp --vault ~/Notes`, or `--stdio` for clients that start the server themselves.

---

# MCP tools

Source: https://developers.lydie.co/mcp/tools

The tools the hosted MCP server at https://api.lydie.co/mcp lists. `run_operation` reaches every other operation by id.

## create_doc

Create document. Writes. Scope: `docs:write`.

Create a document. Creates a document in a workspace, optionally under a parent and with an initial Markdown body. Without afterId/beforeId it is appended as the last child.

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id. Generated when omitted.
- `parentId` (ULID, optional, nullable): Default: `null`.
- `title` (string, optional): Default: `"Untitled"`. (1–255 chars)
- `properties` (object, optional): Default: `{}`.
- `markdown` (string, optional): Initial body as Lydie Markdown.
- `teamspaceId` (string, optional, nullable): Hosted: the teamspace a top-level page goes into (null or absent: the creator's private section). Ignored for child pages, which share their parent's space, and in local mode. (1–64 chars)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key. Overrides afterId/beforeId; recorded by clients so replays converge. (1–256 chars)

## rename_doc

Rename document. Writes. Scope: `docs:write`.

Rename a document.

- `id` (ULID, required)
- `title` (string, required): (1–255 chars)

## move_doc

Move document. Writes. Scope: `docs:write`.

Move a document. Moves a document (and its subtree) under a new parent, or to the top level with parentId null. Without afterId/beforeId it becomes the last child.

- `id` (ULID, required)
- `parentId` (ULID, required, nullable)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key. Overrides afterId/beforeId; recorded by clients so replays converge. (1–256 chars)

## delete_doc

Delete document. Destructive. Scope: `docs:write`.

Delete a document. Soft-deletes a document and its subtree. Restore it with doc.restore. Deleting a deleted document is a no-op.

- `id` (ULID, required)

## restore_doc

Restore document. Writes. Scope: `docs:write`.

Restore a deleted document. Restores a soft-deleted document and the part of its subtree deleted with it. If its parent is gone it is restored to the top level.

- `id` (ULID, required)

## purge_doc

Permanently delete document. Destructive. Scope: `docs:write`.

Permanently delete a document. Permanently deletes a document in the trash, its trashed subtree, bodies and outgoing links. Links to it become unresolved. Cannot be undone.

- `id` (ULID, required)

## set_doc_properties

Set document properties. Writes. Scope: `docs:write`.

Set document properties. Merges `set` into the document's properties and removes the keys in `unset`.

- `id` (ULID, required)
- `set` (object, optional): Default: `{}`.
- `unset` (string[], optional): Default: `[]`.

## update_doc

Update document body. Writes. Scope: `docs:write`.

Update a document body. Replaces the body with `markdown`, or applies `edits` (exact old/new string replacements against the Markdown returned by doc.get). Edits that do not match exactly once are skipped and reported in `warnings`. Pass `expectedVersion` to fail with a conflict if the body changed since you read it.

- `id` (ULID, required)
- `markdown` (string, optional)
- `edits` (BodyEditInput[], optional): (≥ 1 items)
  - `oldStr` (string, required): (≥ 1 chars)
  - `newStr` (string, required)
  - `replaceAll` (boolean, optional): Default: `false`.
- `expectedVersion` (string, optional)

## fetch_doc

Fetch document. Read-only. Scope: `docs:read`.

Get a document. Returns a document's metadata and, unless includeBody is false, its Markdown body.

- `id` (ULID, required)
- `includeBody` (boolean, optional): Default: `true`.

## list_docs

List documents. Read-only. Scope: `docs:read`.

List the document tree. Lists documents depth-first in tree order. With rootId, lists that document's descendants only.

- `workspaceId` (string, required): (1–64 chars)
- `rootId` (ULID, optional)
- `includeDeleted` (boolean, optional): Default: `false`.

## list_children

List child documents. Read-only. Scope: `docs:read`.

List a document's children. Lists the direct children of a document (or the top level when parentId is omitted) in order, each with its number of live children. Use it to load a tree level by level.

- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, optional): Omit for the top level.
- `includeDeleted` (boolean, optional): Default: `false`.

## search

Search documents. Read-only. Scope: `docs:read`.

Search documents. Full-text search over titles and bodies. Words are matched as prefixes; all words must match.

- `workspaceId` (string, required): (1–64 chars)
- `query` (string, required): (1–500 chars)
- `limit` (integer, optional): Default: `20`. (1–50)

## list_backlinks

List backlinks. Read-only. Scope: `docs:read`.

List backlinks. Lists live documents that link to this document.

- `id` (ULID, required)

## list_block_backlinks

List block backlinks. Read-only. Scope: `docs:read`.

List backlinks to a block. Lists live documents that link to one block (`[[Note#^blockId]]`) of this document.

- `id` (ULID, required)
- `blockId` (string, required)

## list_outgoing_links

List outgoing links. Read-only. Scope: `docs:read`.

List outgoing links. Lists the links in this document (body first, then properties, in document order), each with the live document it resolves to or null.

- `id` (ULID, required)

## list_unlinked_mentions

List unlinked mentions. Read-only. Scope: `docs:read`.

List unlinked mentions. Lists live documents whose text mentions this document's title without linking to it.

- `id` (ULID, required)
- `limit` (integer, optional): Default: `50`. (1–100)

## list_unresolved_links

List unresolved links. Read-only. Scope: `docs:read`.

List unresolved links. Lists links in live documents whose target does not exist (yet).

- `workspaceId` (string, required): (1–64 chars)

## list_trash

List trash. Read-only. Scope: `docs:read`.

List the trash. Lists what is in a workspace's trash, newest first. A document deleted with its subtree is one item; restoring it restores the subtree.

- `workspaceId` (string, required): (1–64 chars)
- `limit` (integer, optional): Default: `100`. (1–500)

## empty_trash

Empty trash. Destructive. Scope: `docs:write`.

Empty the trash. Permanently deletes everything in a workspace's trash. Cannot be undone.

- `workspaceId` (string, required): (1–64 chars)

## create_attachment

Add attachment. Writes. Scope: `docs:write`.

Add an attachment. Records an attachment whose bytes are already stored under their SHA-256 (the Blob port locally, an upload URL when hosted). Several attachments may share the same bytes.

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id. Generated when omitted.
- `documentId` (ULID, optional, nullable): Default: `null`.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)

## delete_attachment

Delete attachment. Destructive. Scope: `docs:write`.

Delete an attachment. Moves an attachment to the trash. Restore it with attachment.restore.

- `id` (ULID, required)

## restore_attachment

Restore attachment. Writes. Scope: `docs:write`.

Restore an attachment.

- `id` (ULID, required)

## purge_attachment

Permanently delete attachment. Destructive. Scope: `docs:write`.

Permanently delete an attachment. Permanently deletes an attachment in the trash. Its bytes are removed when no other attachment uses them. Cannot be undone.

- `id` (ULID, required)

## get_attachment

Get attachment. Read-only. Scope: `docs:read`.

Get an attachment.

- `id` (ULID, required)

## list_attachments

List attachments. Read-only. Scope: `docs:read`.

List attachments. Lists a workspace's attachments, or one document's, newest first.

- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, optional)
- `includeDeleted` (boolean, optional): Default: `false`.

## list_sessions

List agent sessions. Read-only. Scope: `docs:read`.

List agent sessions. Lists sessions that changed a workspace, most recent first.

- `workspaceId` (string, optional): (1–64 chars)
- `limit` (integer, optional): Default: `50`. (1–200)

## list_session_changes

List session changes. Read-only. Scope: `docs:read`.

List a session's changes. Lists every operation a session applied, oldest first.

- `sessionId` (string, required): (≥ 1 chars)
- `limit` (integer, optional): Default: `200`. (1–1000)

## undo_session

Undo session. Writes. Scope: `docs:write`.

Undo a session. Reverts every change a session made, newest first, as one undoable step. Changes that later edits by others touched are skipped and reported, as are changes that cannot be undone.

- `sessionId` (string, required): (≥ 1 chars)

## create_database

Create database. Writes. Scope: `docs:write`.

Create a database. Creates a database: a document whose children are its rows. With documentId, turns an existing document into a database (its children become rows). Starts with a title property and one view.

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id of the new database document.
- `documentId` (ULID, optional): Turn this existing document into a database.
- `parentId` (ULID, optional, nullable): Default: `null`.
- `title` (string, optional): Default: `"Untitled database"`. (1–255 chars)
- `teamspaceId` (string, optional, nullable): Hosted: the teamspace a new top-level database goes into (null or absent: the creator's private section). Ignored with parentId or documentId, and in local mode. (1–64 chars)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)
- `viewType` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`. Default: `"table"`.
- `titlePropertyId` (ULID, optional)
- `viewId` (ULID, optional)

## get_database

Get database. Read-only. Scope: `docs:read`.

Get a database. Returns a database's settings, live properties and views, in order.

- `id` (ULID, required)

## list_databases

List databases. Read-only. Scope: `docs:read`.

List databases. Lists the live databases of a workspace (database documents not in the trash).

- `workspaceId` (string, required): (1–64 chars)

## query_database

Query database. Read-only. Scope: `docs:read`.

Query a database. Returns one window of a view's rows (filtered, sorted, grouped), with the total and group counts. Pass viewId for a saved view, or view for an ad-hoc one (both: view overrides). uniqueId values are numbers (shown as prefix-number, e.g. LYD-12); filters take 12 or "LYD-12".

- `databaseId` (ULID, required)
- `viewId` (ULID, optional)
- `view` (object, optional)
  - `type` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`. Default: `"table"`.
  - `config` (ViewConfigPatchInput, optional): Default: `{}`.
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `window` (object, optional): Default: `{"offset":0,"limit":100}`.
  - `offset` (integer, optional): Default: `0`.
  - `limit` (integer, optional): Default: `100`. (0–1000)
  - `group` (string, optional, nullable)
  - `subGroup` (string, optional, nullable)
  - `range` (object, optional)
    - `propertyId` (ULID, optional): Default: the view's calendar property.
    - `start` (string, required): Inclusive, YYYY-MM-DD
    - `end` (string, required): Exclusive, YYYY-MM-DD
- `today` (string, optional): The caller's local date for relative date filters. Default: the server's.

## write_database_rows

Write database rows. Destructive. Scope: `docs:write`.

Write database rows. Creates, updates and deletes rows in one step. A row without id is created; with id it is updated (title renames it); delete: true moves it to the trash. values are keyed by property id, frontmatter key or name; relation values are row ids; select values are option names (new names become options); uniqueId values are numbers (pass 12 or "LYD-12"; new rows get the next number). unset clears properties.

- `databaseId` (ULID, required)
- `rows` (object[], required): (1–1000 items)
  - `id` (ULID, optional): An existing row to update or delete.
  - `title` (string, optional): (1–255 chars)
  - `values` (object, optional): Default: `{}`.
  - `unset` (string[], optional): Default: `[]`.
  - `delete` (boolean, optional): Default: `false`.

## change_database_schema

Change database properties. Destructive. Scope: `docs:write`.

Change a database's properties. Adds, changes and removes properties in one step. update can rename (name), change the type (values are converted), the frontmatter key or the config (options, relation, number format, formula expression). Removed properties keep their values in the rows.

- `databaseId` (ULID, required)
- `add` (object[], optional): Default: `[]`.
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, optional): (1–128 chars)
  - `config` (PropertyConfigSpecInput, optional)
    - `options` (object[], optional): select, multiSelect, status
      - `id` (ULID, optional)
      - `name` (string, required): (1–200 chars)
      - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfigInput, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, optional): Default: `false`.
      - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfigInput, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
- `update` (object[], optional): Default: `[]`.
  - `property` (string, required): A property's id, frontmatter key or name (case-insensitive). (≥ 1 chars)
  - `name` (string, optional): (1–200 chars)
  - `type` (string, optional): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, optional): (1–128 chars)
  - `config` (PropertyConfigSpecInput, optional)
    - `options` (object[], optional): select, multiSelect, status
      - `id` (ULID, optional)
      - `name` (string, required): (1–200 chars)
      - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfigInput, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, optional): Default: `false`.
      - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfigInput, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
- `remove` (string[], optional): Default: `[]`.

## change_database_views

Change database views. Destructive. Scope: `docs:write`.

Change a database's views. Adds, changes and removes views in one step. config is merged into the view's config (filter, sorts, groupBy, columns, …); see get_database for the current values.

- `databaseId` (ULID, required)
- `add` (object[], optional): Default: `[]`.
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfigPatchInput, optional)
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `update` (object[], optional): Default: `[]`.
  - `view` (string, required): A view's id or name (case-insensitive). (≥ 1 chars)
  - `name` (string, optional): (1–200 chars)
  - `type` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfigPatchInput, optional)
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `remove` (string[], optional): Default: `[]`.

## run_operation

Run an operation. Destructive.

Runs any Lydie operation by id with its input, including these not listed as tools: database.update: Update database settings; database.delete: Turn a database back into a page; database.restore: Restore a database; database.setDefinition: Replace a database's schema and views; database.listTemplates: List row templates; database.addProperty: Add a database property; database.renameProperty: Rename a database property; database.updateProperty: Update a database property; database.changePropertyType: Change a property's type; database.moveProperty: Reorder a database property; database.deleteProperty: Delete a database property; database.restoreProperty: Restore a database property; database.addOption: Add a select option; database.updateOption: Rename or recolour a select option; database.moveOption: Reorder a select option; database.deleteOption: Delete a select option; database.createView: Create a database view; database.renameView: Rename a database view; database.duplicateView: Duplicate a database view; database.moveView: Reorder a database view; database.updateView: Update a database view; database.deleteView: Delete a database view; database.restoreView: Restore a database view; database.createRow: Create a database row; database.setValues: Set row values; database.moveRow: Move a database row; database.duplicateRows: Duplicate database rows; database.deleteRows: Delete database rows; database.restoreRows: Restore database rows. Get an operation's input schema with describe_operation.

- `operation` (string, required): Operation id, e.g. doc.move. One of: `doc.create`, `doc.rename`, `doc.move`, `doc.delete`, `doc.restore`, `doc.purge`, `doc.setProperties`, `doc.updateBody`, `doc.get`, `doc.listTree`, `doc.listChildren`, `doc.search`, `doc.backlinks`, `doc.blockBacklinks`, `doc.outgoingLinks`, `doc.unlinkedMentions`, `doc.unresolvedLinks`, `trash.list`, `trash.empty`, `attachment.create`, `attachment.delete`, `attachment.restore`, `attachment.purge`, `attachment.get`, `attachment.list`, `history.listSessions`, `history.listBySession`, `history.undoSession`, `database.create`, `database.update`, `database.delete`, `database.restore`, `database.setDefinition`, `database.get`, `database.listTemplates`, `database.list`, `database.query`, `database.addProperty`, `database.renameProperty`, `database.updateProperty`, `database.changePropertyType`, `database.moveProperty`, `database.deleteProperty`, `database.restoreProperty`, `database.addOption`, `database.updateOption`, `database.moveOption`, `database.deleteOption`, `database.createView`, `database.renameView`, `database.duplicateView`, `database.moveView`, `database.updateView`, `database.deleteView`, `database.restoreView`, `database.createRow`, `database.setValues`, `database.moveRow`, `database.duplicateRows`, `database.deleteRows`, `database.restoreRows`, `database.writeRows`, `database.changeSchema`, `database.changeViews`.
- `input` (object, required): The operation's input.

## describe_operation

Describe an operation. Read-only.

Returns an operation's description and input and output JSON Schemas, for run_operation.

- `operation` (string, required): Operation id, e.g. doc.move. One of: `doc.create`, `doc.rename`, `doc.move`, `doc.delete`, `doc.restore`, `doc.purge`, `doc.setProperties`, `doc.updateBody`, `doc.get`, `doc.listTree`, `doc.listChildren`, `doc.search`, `doc.backlinks`, `doc.blockBacklinks`, `doc.outgoingLinks`, `doc.unlinkedMentions`, `doc.unresolvedLinks`, `trash.list`, `trash.empty`, `attachment.create`, `attachment.delete`, `attachment.restore`, `attachment.purge`, `attachment.get`, `attachment.list`, `history.listSessions`, `history.listBySession`, `history.undoSession`, `database.create`, `database.update`, `database.delete`, `database.restore`, `database.setDefinition`, `database.get`, `database.listTemplates`, `database.list`, `database.query`, `database.addProperty`, `database.renameProperty`, `database.updateProperty`, `database.changePropertyType`, `database.moveProperty`, `database.deleteProperty`, `database.restoreProperty`, `database.addOption`, `database.updateOption`, `database.moveOption`, `database.deleteOption`, `database.createView`, `database.renameView`, `database.duplicateView`, `database.moveView`, `database.updateView`, `database.deleteView`, `database.restoreView`, `database.createRow`, `database.setValues`, `database.moveRow`, `database.duplicateRows`, `database.deleteRows`, `database.restoreRows`, `database.writeRows`, `database.changeSchema`, `database.changeViews`.

---

# Documents and Markdown

Source: https://developers.lydie.co/documents

> How pages, bodies, properties, links and the trash work, and how to edit a body safely while people are typing in it.

Everything in a workspace is a document: notes, pages, database rows. Documents form a tree.

## The document

| Field                    | What it holds                                                                    |
| ------------------------ | -------------------------------------------------------------------------------- |
| `id`                     | A ULID. You may choose it when you create the document, or let Lydie make one.   |
| `parentId`               | The parent document, or `null` at the top level.                                 |
| `title`                  | 1 to 255 characters.                                                             |
| `properties`             | Typed frontmatter: strings, numbers, booleans, `null` or lists of strings.       |
| `sortKey`                | Its place among its siblings. Use `afterId` or `beforeId` instead of setting it. |
| `createdBy`, `updatedBy` | Who made the change: a user id, or `agent:<app>:<id>:<user id>` for an agent.    |
| `deletedAt`              | Set while the document is in the trash.                                          |

The body is not part of the document. [Get a document](https://developers.lydie.co/api/documents/get-a-document.md) returns both,
and `includeBody=false` leaves the body out.

A new top-level page goes to your private section unless you pass `teamspaceId`. Subpages always
live in their parent's space.

## Bodies are Markdown

A body is Lydie Markdown: CommonMark with GitHub's tables, task lists, strikethrough, autolinks and
footnotes, plus Obsidian's syntax.

| Syntax                                   | Meaning                             |
| ---------------------------------------- | ----------------------------------- |
| `[[Note]]`, `[[Note\|alias]]`            | A link to another document by title |
| `[[Note#Heading]]`, `[[Note#^block-id]]` | A link to a heading or a block      |
| `![[image.png]]`, `![[Note]]`            | An embedded file or document        |
| `text ^block-id`                         | A block id that links can point at  |
| `> [!note] Title`                        | A callout                           |
| `==text==`, `%%comment%%`, `#tag`, `$x$` | Highlight, comment, tag, math       |

Frontmatter is not part of the body. Read and write it as `properties`.

## Edit a body

[Update a document body](https://developers.lydie.co/api/documents/update-a-document-body.md) takes one of two inputs:

- `markdown` replaces the whole body.
- `edits` is a list of exact replacements, `{ "oldStr": "…", "newStr": "…" }`, matched against the
  Markdown you read. Set `replaceAll: true` to change every match.

Prefer `edits`. They touch only what you change, so they do not undo what someone typed after you
read the page. An edit that does not match exactly once is skipped and listed in `warnings` with
the code `no_match` or `ambiguous_match`. The rest still apply.

Each read returns a `version`. Send it back as `expectedVersion` and the write fails with
`409 conflict` if the body changed since you read it. Read again and retry.

Writes merge into the live document. Someone with the page open sees your change appear.

## Properties

[Set document properties](https://developers.lydie.co/api/documents/set-document-properties.md) merges `set` into the existing
properties and removes the keys in `unset`:

```json
{ "set": { "status": "done", "tags": ["docs"] }, "unset": ["due"] }
```

## Links

Lydie indexes every link in every body. Use these to follow them:

- [List backlinks](https://developers.lydie.co/api/documents/list-backlinks.md): documents that link here.
- [List outgoing links](https://developers.lydie.co/api/documents/list-outgoing-links.md): links in this document and where they
  resolve.
- [List unresolved links](https://developers.lydie.co/api/documents/list-unresolved-links.md): links to pages that do not exist
  yet.
- [List unlinked mentions](https://developers.lydie.co/api/documents/list-unlinked-mentions.md): documents that mention this
  title without linking it.

## Search

[Search documents](https://developers.lydie.co/api/documents/search-documents.md) searches titles and bodies. Every word must
match, as a prefix. Snippets wrap matches in `<mark></mark>`.

## Delete, restore, purge

Deleting moves a document and its subpages to the [trash](https://developers.lydie.co/api/trash.md), and restoring brings them
back. Purging deletes a trashed document for good, along with its body. Links to it become
unresolved. Purging cannot be undone.

---

# Agent changes and undo

Source: https://developers.lydie.co/agent-history

> Lydie records which agent made each change and for whom, and can undo everything one agent session did in one step.

Lydie treats agents as their own kind of author. People can see what an agent changed and undo it
without losing their own work.

## Who made a change

Every write records an actor:

| Actor  | Recorded as                  | Example                     |
| ------ | ---------------------------- | --------------------------- |
| User   | The user id                  | A person typing in the app  |
| Agent  | `agent:<app>:<id>:<user id>` | An API token, an MCP client |
| System | `system:<id>`                | Lydie itself                |

The `app` of an agent is `api-token` for personal API tokens, or the client's name for OAuth apps.
`<user id>` is the person the agent acts for. This value is what `createdBy` and `updatedBy` hold
on documents.

## Sessions

Changes made over [MCP](https://developers.lydie.co/mcp.md) are grouped into a session, one per credential. Each API token is one
session, and so is each app you approved with OAuth. The session stays the same when an OAuth app
refreshes its token.

| MCP tool               | REST                                                             |
| ---------------------- | ---------------------------------------------------------------- |
| `list_sessions`        | [List agent sessions](https://developers.lydie.co/api/history/list-agent-sessions.md)          |
| `list_session_changes` | [List a session's changes](https://developers.lydie.co/api/history/list-a-sessions-changes.md) |
| `undo_session`         | [Undo a session](https://developers.lydie.co/api/history/undo-a-session.md)                    |

The MCP server tells the agent its session id when it connects, so an agent can review its own
work.

## Undo a session

Undoing a session reverts its changes newest first, as one step that can itself be undone. If
someone else has since changed something the agent touched, that change is skipped and reported,
so their work is kept.

Most changes can be undone; the reference marks those that can. Permanent deletions (purging a
document, emptying the trash) cannot be undone.

---

# Errors and versions

Source: https://developers.lydie.co/errors

> The error envelope and its codes, warnings on partial success, and how the API is versioned.

## The error envelope

Every error has the same shape and an HTTP status that matches its code:

```json
{
  "error": {
    "code": "forbidden",
    "message": "This API token lacks the scope docs:write",
    "hint": "Optional advice on what to do next",
    "details": { "required": ["docs:write"], "granted": ["docs:read"] }
  }
}
```

`message` is written for people and may change. Branch on `code`. `hint` and `details` are
optional.

| Status | Code                | Meaning                                                                                               |
| ------ | ------------------- | ----------------------------------------------------------------------------------------------------- |
| 400    | `invalid_input`     | The input does not match the schema. `details` may list the problems.                                 |
| 401    | `unauthenticated`   | No token, or the token was revoked or has expired.                                                    |
| 403    | `forbidden`         | You lack access to the page, the token lacks a scope, or the operation needs a signed-in session.     |
| 404    | `not_found`         | It does not exist, or you cannot see it.                                                              |
| 404    | `unknown_operation` | No such operation.                                                                                    |
| 409    | `conflict`          | The data changed since you read it (`expectedVersion`), or the change clashes with the current state. |
| 429    | `rate_limited`      | Too many attempts. Wait for the `Retry-After` seconds.                                                |
| 500    | `internal`          | Our fault. Retry later.                                                                               |

## Warnings

Some operations succeed partly. A body edit that matched nothing is skipped while the other edits
apply. The result then lists `warnings`, and the response also carries them in the
`Lydie-Warnings` header as a JSON array.

## Versions

The API is versioned by date. The current version is `2026-11-12`. Pin the version you built
against by sending it with each request:

```http
Lydie-Version: 2026-11-12
```

The [OpenAPI document](https://developers.lydie.co/openapi.json) always describes the current version.

---

# Lydie API

Source: https://developers.lydie.co/api

- Base URL: `https://api.lydie.co/v1`
- Authentication: `Authorization: Bearer <token>`. See https://developers.lydie.co/authentication.md.
- Requests and responses are JSON. GET and DELETE take their input as query parameters; other methods take a JSON body. Path parameters are part of the input.
- IDs of documents are ULIDs. Timestamps are ISO 8601 in UTC.
- Errors: `{ "error": { "code", "message", "hint"?, "details"? } }`. See https://developers.lydie.co/errors.md.
- Version: `2026-11-12` (`Lydie-Version` header).
- OpenAPI 3.1 document: https://developers.lydie.co/openapi.json

## Resources

- [Documents](https://developers.lydie.co/api/documents.md): Pages in a workspace: a tree of documents, each with a title, typed properties (frontmatter) and a Markdown body.
- [Databases](https://developers.lydie.co/api/databases.md): A database is a document whose children are its rows. Each row is a document; its values are the row's properties.
- [Attachments](https://developers.lydie.co/api/attachments.md): Files attached to a workspace or a document, stored by their SHA-256 hash. Upload the bytes first, then record the attachment.
- [Trash](https://developers.lydie.co/api/trash.md): Deleted documents and attachments stay in the trash until they are restored or purged.
- [History](https://developers.lydie.co/api/history.md): Sessions group the changes an agent made, so they can be reviewed and undone together.
- [Workspaces](https://developers.lydie.co/api/workspaces.md): A workspace holds documents, members and teamspaces. An API token belongs to exactly one.
- [Members](https://developers.lydie.co/api/members.md): People in a workspace and their roles: owner, admin, member or guest.
- [Teamspaces](https://developers.lydie.co/api/teamspaces.md): Groups of pages with their own members. Open teamspaces are visible to every member; closed and private ones are not.
- [Invitations](https://developers.lydie.co/api/invitations.md): Email invitations to join a workspace.
- [Sharing](https://developers.lydie.co/api/sharing.md): Who can see a page: grants to people, teamspaces or the whole workspace, restricted pages, and public links.
- [Notifications](https://developers.lydie.co/api/notifications.md): Your inbox: mentions, shares and accepted invitations.
- [Publishing](https://developers.lydie.co/api/publishing.md): Publish documents to GitHub, WordPress or a webhook. A connection holds the credentials; a publication says what goes where.
- [API tokens](https://developers.lydie.co/api/api-tokens.md): Personal API tokens. These endpoints need a signed-in session: a token cannot create or list tokens.
- [Connected apps](https://developers.lydie.co/api/connected-apps.md): Apps you allowed through OAuth, such as MCP clients. Signed-in session only.

---

# Documents

Source: https://developers.lydie.co/api/documents

Pages in a workspace: a tree of documents, each with a title, typed properties (frontmatter) and a Markdown body.

## Endpoints

- [Create a document](https://developers.lydie.co/api/documents/create-a-document.md): `POST /v1/documents`
- [Get a document](https://developers.lydie.co/api/documents/get-a-document.md): `GET /v1/documents/{id}`
- [Delete a document](https://developers.lydie.co/api/documents/delete-a-document.md): `DELETE /v1/documents/{id}`
- [List backlinks](https://developers.lydie.co/api/documents/list-backlinks.md): `GET /v1/documents/{id}/backlinks`
- [List backlinks to a block](https://developers.lydie.co/api/documents/list-backlinks-to-a-block.md): `GET /v1/documents/{id}/blocks/{blockId}/backlinks`
- [Update a document body](https://developers.lydie.co/api/documents/update-a-document-body.md): `PATCH /v1/documents/{id}/body`
- [List outgoing links](https://developers.lydie.co/api/documents/list-outgoing-links.md): `GET /v1/documents/{id}/links`
- [Move a document](https://developers.lydie.co/api/documents/move-a-document.md): `POST /v1/documents/{id}/move`
- [Set document properties](https://developers.lydie.co/api/documents/set-document-properties.md): `PATCH /v1/documents/{id}/properties`
- [Permanently delete a document](https://developers.lydie.co/api/documents/permanently-delete-a-document.md): `POST /v1/documents/{id}/purge`
- [Rename a document](https://developers.lydie.co/api/documents/rename-a-document.md): `POST /v1/documents/{id}/rename`
- [Restore a deleted document](https://developers.lydie.co/api/documents/restore-a-deleted-document.md): `POST /v1/documents/{id}/restore`
- [Move a page to another teamspace or to Private](https://developers.lydie.co/api/documents/move-a-page-to-another-teamspace-or-to-private.md): `POST /v1/documents/{id}/space`
- [List unlinked mentions](https://developers.lydie.co/api/documents/list-unlinked-mentions.md): `GET /v1/documents/{id}/unlinked-mentions`
- [List a document's versions](https://developers.lydie.co/api/documents/list-a-documents-versions.md): `GET /v1/documents/{id}/versions`
- [Get a document version](https://developers.lydie.co/api/documents/get-a-document-version.md): `GET /v1/documents/{id}/versions/{versionId}`
- [Restore a document version](https://developers.lydie.co/api/documents/restore-a-document-version.md): `POST /v1/documents/{id}/versions/{versionId}/restore`
- [List a document's children](https://developers.lydie.co/api/documents/list-a-documents-children.md): `GET /v1/workspaces/{workspaceId}/children`
- [Search documents](https://developers.lydie.co/api/documents/search-documents.md): `GET /v1/workspaces/{workspaceId}/search`
- [List the document tree](https://developers.lydie.co/api/documents/list-the-document-tree.md): `GET /v1/workspaces/{workspaceId}/tree`
- [List unresolved links](https://developers.lydie.co/api/documents/list-unresolved-links.md): `GET /v1/workspaces/{workspaceId}/unresolved-links`

## The Document object

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

---

# Create a document

Source: https://developers.lydie.co/api/documents/create-a-document

`POST /v1/documents`

Creates a document in a workspace, optionally under a parent and with an initial Markdown body. Without afterId/beforeId it is appended as the last child.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "title": "Meeting notes",
    "markdown": "# Meeting notes\n\n- Ship the developer docs"
  }'
```

## Body

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id. Generated when omitted.
- `parentId` (ULID, optional, nullable): Default: `null`.
- `title` (string, optional): Default: `"Untitled"`. (1–255 chars)
- `properties` (object, optional): Default: `{}`.
- `markdown` (string, optional): Initial body as Lydie Markdown.
- `teamspaceId` (string, optional, nullable): Hosted: the teamspace a top-level page goes into (null or absent: the creator's private section). Ignored for child pages, which share their parent's space, and in local mode. (1–64 chars)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key. Overrides afterId/beforeId; recorded by clients so replays converge. (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a document

Source: https://developers.lydie.co/api/documents/get-a-document

`GET /v1/documents/{id}`

Returns a document's metadata and, unless includeBody is false, its Markdown body.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Query parameters

- `includeBody` (boolean, optional): Default: `true`.

## Response

- `document` (Document, required): Document metadata. The body is not part of it.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `body` (DocumentBody, required, nullable)
  - `markdown` (string, required)
  - `version` (string, required): Opaque content version; pass it as expectedVersion.

```json
{
  "document": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "parentId": null,
    "title": "Meeting notes",
    "sortKey": "a0",
    "properties": {
      "status": "draft"
    },
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "body": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete a document

Source: https://developers.lydie.co/api/documents/delete-a-document

`DELETE /v1/documents/{id}`

Soft-deletes a document and its subtree. Restore it with doc.restore. Deleting a deleted document is a no-op.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `deletedAt` (timestamp, required)
- `deletedIds` (ULID[], required)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "deletedAt": "2026-11-12T09:30:00.000Z",
  "deletedIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List backlinks

Source: https://developers.lydie.co/api/documents/list-backlinks

`GET /v1/documents/{id}/backlinks`

Lists live documents that link to this document.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/backlinks" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `backlinks` (Backlink[], required)
  - `source` (object, required)
    - `id` (ULID, required)
    - `title` (string, required): (1–255 chars)
    - `parentId` (ULID, required, nullable)
    - `workspaceId` (string, required): (1–64 chars)
  - `kind` (string, required): One of: `link`, `embed`.
  - `syntax` (string, required): One of: `wikilink`, `markdown`.
  - `targetRef` (string, required)
  - `sourceBlockId` (string, required, nullable)
  - `targetHeading` (string, required, nullable)
  - `targetBlockId` (string, required, nullable)
  - `sourceProperty` (string, optional, nullable): Set when the link is in a property (a relation value or a [[link]]).

```json
{
  "backlinks": [
    {
      "source": {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "title": "Meeting notes",
        "parentId": null,
        "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
      },
      "kind": "link",
      "syntax": "wikilink",
      "targetRef": "string",
      "sourceBlockId": null,
      "targetHeading": null,
      "targetBlockId": null,
      "sourceProperty": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List backlinks to a block

Source: https://developers.lydie.co/api/documents/list-backlinks-to-a-block

`GET /v1/documents/{id}/blocks/{blockId}/backlinks`

Lists live documents that link to one block (`[[Note#^blockId]]`) of this document.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/blocks/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/backlinks" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)
- `blockId` (string, required)

## Response

- `backlinks` (Backlink[], required)
  - `source` (object, required)
    - `id` (ULID, required)
    - `title` (string, required): (1–255 chars)
    - `parentId` (ULID, required, nullable)
    - `workspaceId` (string, required): (1–64 chars)
  - `kind` (string, required): One of: `link`, `embed`.
  - `syntax` (string, required): One of: `wikilink`, `markdown`.
  - `targetRef` (string, required)
  - `sourceBlockId` (string, required, nullable)
  - `targetHeading` (string, required, nullable)
  - `targetBlockId` (string, required, nullable)
  - `sourceProperty` (string, optional, nullable): Set when the link is in a property (a relation value or a [[link]]).

```json
{
  "backlinks": [
    {
      "source": {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "title": "Meeting notes",
        "parentId": null,
        "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
      },
      "kind": "link",
      "syntax": "wikilink",
      "targetRef": "string",
      "sourceBlockId": null,
      "targetHeading": null,
      "targetBlockId": null,
      "sourceProperty": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Update a document body

Source: https://developers.lydie.co/api/documents/update-a-document-body

`PATCH /v1/documents/{id}/body`

Replaces the body with `markdown`, or applies `edits` (exact old/new string replacements against the Markdown returned by doc.get). Edits that do not match exactly once are skipped and reported in `warnings`. Pass `expectedVersion` to fail with a conflict if the body changed since you read it.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/body" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "edits": [
      {
        "oldStr": "Ship the developer docs",
        "newStr": "Shipped the developer docs"
      }
    ]
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `markdown` (string, optional)
- `edits` (BodyEditInput[], optional): (≥ 1 items)
  - `oldStr` (string, required): (≥ 1 chars)
  - `newStr` (string, required)
  - `replaceAll` (boolean, optional): Default: `false`.
- `expectedVersion` (string, optional)

## Response

- `document` (Document, required): Document metadata. The body is not part of it.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `version` (string, required)
- `warnings` (Warning[], required)
  - `code` (string, required): One of: `no_match`, `ambiguous_match`.
  - `message` (string, required)
  - `editIndex` (integer, optional)

```json
{
  "document": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "parentId": null,
    "title": "Meeting notes",
    "sortKey": "a0",
    "properties": {
      "status": "draft"
    },
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "version": "3f9c2a71",
  "warnings": [
    {
      "code": "no_match",
      "message": "string",
      "editIndex": 0
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List outgoing links

Source: https://developers.lydie.co/api/documents/list-outgoing-links

`GET /v1/documents/{id}/links`

Lists the links in this document (body first, then properties, in document order), each with the live document it resolves to or null.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/links" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `links` (OutgoingLink[], required)
  - `id` (ULID, required)
  - `kind` (string, required): One of: `link`, `embed`.
  - `syntax` (string, required): One of: `wikilink`, `markdown`.
  - `targetRef` (string, required): The link target as written (path or title, without #part).
  - `targetHeading` (string, required, nullable)
  - `targetBlockId` (string, required, nullable)
  - `sourceBlockId` (string, required, nullable)
  - `sourceProperty` (string, optional, nullable)
  - `target` (object, required, nullable): The live document it resolves to; null when it resolves to nothing or to the trash.
    - `id` (ULID, required)
    - `title` (string, required): (1–255 chars)
    - `parentId` (ULID, required, nullable)
    - `workspaceId` (string, required): (1–64 chars)

```json
{
  "links": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "kind": "link",
      "syntax": "wikilink",
      "targetRef": "string",
      "targetHeading": null,
      "targetBlockId": null,
      "sourceBlockId": null,
      "sourceProperty": null,
      "target": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Move a document

Source: https://developers.lydie.co/api/documents/move-a-document

`POST /v1/documents/{id}/move`

Moves a document (and its subtree) under a new parent, or to the top level with parentId null. Without afterId/beforeId it becomes the last child.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/move" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "parentId": null
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `parentId` (ULID, required, nullable)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key. Overrides afterId/beforeId; recorded by clients so replays converge. (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Set document properties

Source: https://developers.lydie.co/api/documents/set-document-properties

`PATCH /v1/documents/{id}/properties`

Merges `set` into the document's properties and removes the keys in `unset`.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/properties" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "set": {
      "status": "done"
    },
    "unset": [
      "due"
    ]
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `set` (object, optional): Default: `{}`.
- `unset` (string[], optional): Default: `[]`.

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Permanently delete a document

Source: https://developers.lydie.co/api/documents/permanently-delete-a-document

`POST /v1/documents/{id}/purge`

Permanently deletes a document in the trash, its trashed subtree, bodies and outgoing links. Links to it become unresolved. Cannot be undone.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/purge" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `purgedIds` (ULID[], required)

```json
{
  "purgedIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Rename a document

Source: https://developers.lydie.co/api/documents/rename-a-document

`POST /v1/documents/{id}/rename`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rename" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Meeting notes"
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `title` (string, required): (1–255 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a deleted document

Source: https://developers.lydie.co/api/documents/restore-a-deleted-document

`POST /v1/documents/{id}/restore`

Restores a soft-deleted document and the part of its subtree deleted with it. If its parent is gone it is restored to the top level.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Move a page to another teamspace or to Private

Source: https://developers.lydie.co/api/documents/move-a-page-to-another-teamspace-or-to-private

`POST /v1/documents/{id}/space`

Moves the page and its subpages to the top level of a teamspace you belong to, or of your private section (teamspaceId null). Needs full access to the page.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/space" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "teamspaceId": null
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `teamspaceId` (string, required, nullable): (1–64 chars)
- `sortKey` (string, optional): Recorded by clients so replays converge. (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List unlinked mentions

Source: https://developers.lydie.co/api/documents/list-unlinked-mentions

`GET /v1/documents/{id}/unlinked-mentions`

Lists live documents whose text mentions this document's title without linking to it.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/unlinked-mentions" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Query parameters

- `limit` (integer, optional): Default: `50`. (1–100)

## Response

- `mentions` (UnlinkedMention[], required)
  - `source` (object, required)
    - `id` (ULID, required)
    - `title` (string, required): (1–255 chars)
    - `parentId` (ULID, required, nullable)
    - `workspaceId` (string, required): (1–64 chars)
  - `snippet` (string, required): Matching excerpt; the mention is wrapped in <mark></mark>.

```json
{
  "mentions": [
    {
      "source": {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "title": "Meeting notes",
        "parentId": null,
        "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
      },
      "snippet": "string"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List a document's versions

Source: https://developers.lydie.co/api/documents/list-a-documents-versions

`GET /v1/documents/{id}/versions`

Lists saved versions of a document's body, newest first.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/versions" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Query parameters

- `limit` (integer, optional): Default: `50`. (1–200)

## Response

- `versions` (DocumentVersion[], required)
  - `id` (string, required)
  - `documentId` (ULID, required)
  - `kind` (string, required): auto: editing went idle. before_write: the state before an API write or restore. restore: the result of a restore. One of: `auto`, `before_write`, `restore`.
  - `authors` (string[], required): Actor refs of whoever changed the body since the previous version.
  - `restoredFrom` (string, required, nullable)
  - `sizeBytes` (integer, required)
  - `createdAt` (string, required)

```json
{
  "versions": [
    {
      "id": "string",
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "kind": "auto",
      "authors": [
        "string"
      ],
      "restoredFrom": null,
      "sizeBytes": -9007199254740991,
      "createdAt": "string"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a document version

Source: https://developers.lydie.co/api/documents/get-a-document-version

`GET /v1/documents/{id}/versions/{versionId}`

Returns one saved version of a document's body as Markdown.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/versions/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)
- `versionId` (string, required): (1–64 chars)

## Response

- `version` (DocumentVersion, required)
  - `id` (string, required)
  - `documentId` (ULID, required)
  - `kind` (string, required): auto: editing went idle. before_write: the state before an API write or restore. restore: the result of a restore. One of: `auto`, `before_write`, `restore`.
  - `authors` (string[], required): Actor refs of whoever changed the body since the previous version.
  - `restoredFrom` (string, required, nullable)
  - `sizeBytes` (integer, required)
  - `createdAt` (string, required)
- `markdown` (string, required)

```json
{
  "version": "3f9c2a71",
  "markdown": "# Meeting notes\n\n- Ship the developer docs"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a document version

Source: https://developers.lydie.co/api/documents/restore-a-document-version

`POST /v1/documents/{id}/versions/{versionId}/restore`

Makes the body read as a saved version again, as a new edit merged into the live document. The body before the restore is kept as a version (`previousVersionId`): restore it to undo.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/versions/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)
- `versionId` (string, required): (1–64 chars)

## Response

- `versionId` (string, required, nullable): The version recording the restored body.
- `previousVersionId` (string, required, nullable): The body before the restore.
- `version` (string, required): The body's new content version (for expectedVersion).

```json
{
  "versionId": null,
  "previousVersionId": null,
  "version": "3f9c2a71"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List a document's children

Source: https://developers.lydie.co/api/documents/list-a-documents-children

`GET /v1/workspaces/{workspaceId}/children`

Lists the direct children of a document (or the top level when parentId is omitted) in order, each with its number of live children. Use it to load a tree level by level.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/children" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `parentId` (ULID, optional): Omit for the top level.
- `includeDeleted` (boolean, optional): Default: `false`.

## Response

- `entries` (ChildEntry[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
  - `childCount` (integer, required): Live children, so a tree can show a disclosure.
  - `teamspaceId` (string, optional, nullable)
  - `privateOwnerId` (string, optional, nullable)

```json
{
  "entries": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "parentId": null,
      "title": "Meeting notes",
      "sortKey": "a0",
      "properties": {
        "status": "draft"
      },
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null,
      "childCount": 0,
      "teamspaceId": null,
      "privateOwnerId": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Search documents

Source: https://developers.lydie.co/api/documents/search-documents

`GET /v1/workspaces/{workspaceId}/search`

Full-text search over titles and bodies. Words are matched as prefixes; all words must match.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/search?query=roadmap" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `query` (string, required): (1–500 chars)
- `limit` (integer, optional): Default: `20`. (1–50)

## Response

- `hits` (SearchHit[], required)
  - `id` (ULID, required)
  - `title` (string, required)
  - `snippet` (string, required): Matching excerpt; matches are wrapped in <mark></mark>.
  - `score` (number, required): Lower is better (bm25).

```json
{
  "hits": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "title": "Meeting notes",
      "snippet": "string",
      "score": 0
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List the document tree

Source: https://developers.lydie.co/api/documents/list-the-document-tree

`GET /v1/workspaces/{workspaceId}/tree`

Lists documents depth-first in tree order. With rootId, lists that document's descendants only.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/tree" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `rootId` (ULID, optional)
- `includeDeleted` (boolean, optional): Default: `false`.

## Response

- `entries` (TreeEntry[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
  - `depth` (integer, required): 0 for the top level of the listed tree.
  - `teamspaceId` (string, optional, nullable)
  - `privateOwnerId` (string, optional, nullable)

```json
{
  "entries": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "parentId": null,
      "title": "Meeting notes",
      "sortKey": "a0",
      "properties": {
        "status": "draft"
      },
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null,
      "depth": 0,
      "teamspaceId": null,
      "privateOwnerId": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List unresolved links

Source: https://developers.lydie.co/api/documents/list-unresolved-links

`GET /v1/workspaces/{workspaceId}/unresolved-links`

Lists links in live documents whose target does not exist (yet).

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/unresolved-links" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `links` (UnresolvedLink[], required)
  - `source` (object, required)
    - `id` (ULID, required)
    - `title` (string, required): (1–255 chars)
    - `parentId` (ULID, required, nullable)
    - `workspaceId` (string, required): (1–64 chars)
  - `kind` (string, required): One of: `link`, `embed`.
  - `syntax` (string, required): One of: `wikilink`, `markdown`.
  - `targetRef` (string, required)

```json
{
  "links": [
    {
      "source": {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "title": "Meeting notes",
        "parentId": null,
        "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
      },
      "kind": "link",
      "syntax": "wikilink",
      "targetRef": "string"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Databases

Source: https://developers.lydie.co/api/databases

A database is a document whose children are its rows. Each row is a document; its values are the row's properties.

## Endpoints

- [Update a database property](https://developers.lydie.co/api/databases/update-a-database-property.md): `PATCH /v1/database-properties/{id}`
- [Delete a database property](https://developers.lydie.co/api/databases/delete-a-database-property.md): `DELETE /v1/database-properties/{id}`
- [Reorder a database property](https://developers.lydie.co/api/databases/reorder-a-database-property.md): `POST /v1/database-properties/{id}/move`
- [Rename a database property](https://developers.lydie.co/api/databases/rename-a-database-property.md): `POST /v1/database-properties/{id}/rename`
- [Restore a database property](https://developers.lydie.co/api/databases/restore-a-database-property.md): `POST /v1/database-properties/{id}/restore`
- [Change a property's type](https://developers.lydie.co/api/databases/change-a-propertys-type.md): `POST /v1/database-properties/{id}/type`
- [Add a select option](https://developers.lydie.co/api/databases/add-a-select-option.md): `POST /v1/database-properties/{propertyId}/options`
- [Rename or recolour a select option](https://developers.lydie.co/api/databases/rename-or-recolour-a-select-option.md): `PATCH /v1/database-properties/{propertyId}/options/{optionId}`
- [Delete a select option](https://developers.lydie.co/api/databases/delete-a-select-option.md): `DELETE /v1/database-properties/{propertyId}/options/{optionId}`
- [Reorder a select option](https://developers.lydie.co/api/databases/reorder-a-select-option.md): `POST /v1/database-properties/{propertyId}/options/{optionId}/move`
- [Move a database row](https://developers.lydie.co/api/databases/move-a-database-row.md): `POST /v1/database-rows/{rowId}/move`
- [Update a database view](https://developers.lydie.co/api/databases/update-a-database-view.md): `PATCH /v1/database-views/{id}`
- [Delete a database view](https://developers.lydie.co/api/databases/delete-a-database-view.md): `DELETE /v1/database-views/{id}`
- [Duplicate a database view](https://developers.lydie.co/api/databases/duplicate-a-database-view.md): `POST /v1/database-views/{id}/duplicate`
- [Reorder a database view](https://developers.lydie.co/api/databases/reorder-a-database-view.md): `POST /v1/database-views/{id}/move`
- [Rename a database view](https://developers.lydie.co/api/databases/rename-a-database-view.md): `POST /v1/database-views/{id}/rename`
- [Restore a database view](https://developers.lydie.co/api/databases/restore-a-database-view.md): `POST /v1/database-views/{id}/restore`
- [Create a database](https://developers.lydie.co/api/databases/create-a-database.md): `POST /v1/databases`
- [Add a database property](https://developers.lydie.co/api/databases/add-a-database-property.md): `POST /v1/databases/{databaseId}/properties`
- [Query a database](https://developers.lydie.co/api/databases/query-a-database.md): `POST /v1/databases/{databaseId}/query`
- [Create a database row](https://developers.lydie.co/api/databases/create-a-database-row.md): `POST /v1/databases/{databaseId}/rows`
- [Set row values](https://developers.lydie.co/api/databases/set-row-values.md): `PATCH /v1/databases/{databaseId}/rows`
- [Delete database rows](https://developers.lydie.co/api/databases/delete-database-rows.md): `POST /v1/databases/{databaseId}/rows/delete`
- [Duplicate database rows](https://developers.lydie.co/api/databases/duplicate-database-rows.md): `POST /v1/databases/{databaseId}/rows/duplicate`
- [Restore database rows](https://developers.lydie.co/api/databases/restore-database-rows.md): `POST /v1/databases/{databaseId}/rows/restore`
- [Write database rows](https://developers.lydie.co/api/databases/write-database-rows.md): `POST /v1/databases/{databaseId}/rows/write`
- [Change a database's properties](https://developers.lydie.co/api/databases/change-a-databases-properties.md): `POST /v1/databases/{databaseId}/schema`
- [List row templates](https://developers.lydie.co/api/databases/list-row-templates.md): `GET /v1/databases/{databaseId}/templates`
- [Create a database view](https://developers.lydie.co/api/databases/create-a-database-view.md): `POST /v1/databases/{databaseId}/views`
- [Change a database's views](https://developers.lydie.co/api/databases/change-a-databases-views.md): `POST /v1/databases/{databaseId}/views/change`
- [Get a database](https://developers.lydie.co/api/databases/get-a-database.md): `GET /v1/databases/{id}`
- [Update database settings](https://developers.lydie.co/api/databases/update-database-settings.md): `PATCH /v1/databases/{id}`
- [Turn a database back into a page](https://developers.lydie.co/api/databases/turn-a-database-back-into-a-page.md): `DELETE /v1/databases/{id}`
- [Replace a database's schema and views](https://developers.lydie.co/api/databases/replace-a-databases-schema-and-views.md): `PUT /v1/databases/{id}/definition`
- [Restore a database](https://developers.lydie.co/api/databases/restore-a-database.md): `POST /v1/databases/{id}/restore`
- [List databases](https://developers.lydie.co/api/databases/list-databases.md): `GET /v1/workspaces/{workspaceId}/databases`

## The Database object

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `config` (DatabaseConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `templateIds` (ULID[], required): Default: `[]`.
  - `extra` (object, required): Default: `{}`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "config": {
    "filter": null,
    "templateIds": [],
    "extra": {}
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

---

# Update a database property

Source: https://developers.lydie.co/api/databases/update-a-database-property

`PATCH /v1/database-properties/{id}`

Replaces the property's configuration and/or its key. A new key moves every row's value to it (one undo step).

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `key` (string, optional): (1–128 chars)
- `config` (PropertyConfigSpecInput, optional)
  - `options` (object[], optional): select, multiSelect, status
    - `id` (ULID, optional)
    - `name` (string, required): (1–200 chars)
    - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfigInput, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, optional): Default: `false`.
    - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfigInput, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete a database property

Source: https://developers.lydie.co/api/databases/delete-a-database-property

`DELETE /v1/database-properties/{id}`

Moves the property to the trash. Row values stay in the documents' properties, so restoring it brings them back. Deleting one side of a two-way relation makes the other side one-way.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Reorder a database property

Source: https://developers.lydie.co/api/databases/reorder-a-database-property

`POST /v1/database-properties/{id}/move`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/move" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Rename a database property

Source: https://developers.lydie.co/api/databases/rename-a-database-property

`POST /v1/database-properties/{id}/rename`

Changes the display name only; the frontmatter key and row values stay (use database.updateProperty with key to rename the key).

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rename" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes"
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `name` (string, required): (1–200 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a database property

Source: https://developers.lydie.co/api/databases/restore-a-database-property

`POST /v1/database-properties/{id}/restore`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a property's type

Source: https://developers.lydie.co/api/databases/change-a-propertys-type

`POST /v1/database-properties/{id}/type`

Changes the type and converts every row's value (see the conversion table in the docs). convert: false keeps the values as they are.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/type" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "title"
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `config` (PropertyConfigSpecInput, optional)
  - `options` (object[], optional): select, multiSelect, status
    - `id` (ULID, optional)
    - `name` (string, required): (1–200 chars)
    - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfigInput, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, optional): Default: `false`.
    - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfigInput, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `convert` (boolean, optional): Default: `true`.

## Response

- `property` (DatabaseProperty, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `converted` (integer, required)

```json
{
  "property": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "name": "Notes",
    "type": "title",
    "key": "string",
    "config": {
      "options": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "name": "Notes",
          "color": "default",
          "group": "todo"
        }
      ],
      "numberFormat": "number",
      "decimals": 0,
      "currency": "string",
      "includeTime": false,
      "range": false,
      "relation": {
        "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "twoWay": false,
        "reversePropertyId": null,
        "limit": "one"
      },
      "rollup": {
        "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "function": "showOriginal"
      },
      "expression": "string",
      "prefix": "string",
      "extra": {}
    },
    "sortKey": "a0",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "converted": 0
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Add a select option

Source: https://developers.lydie.co/api/databases/add-a-select-option

`POST /v1/database-properties/{propertyId}/options`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/options" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "option": {
      "name": "Notes"
    }
  }'
```

## Path parameters

- `propertyId` (ULID, required)

## Body

- `option` (object, required)
  - `id` (ULID, optional)
  - `name` (string, required): (1–200 chars)
  - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
  - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
- `index` (integer, optional): Default: last.

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Rename or recolour a select option

Source: https://developers.lydie.co/api/databases/rename-or-recolour-a-select-option

`PATCH /v1/database-properties/{propertyId}/options/{optionId}`

Rows store the option's name, so renaming rewrites the rows that use it (one undo step).

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/options/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `propertyId` (ULID, required)
- `optionId` (ULID, required)

## Body

- `name` (string, optional): (1–200 chars)
- `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
- `group` (string, optional): One of: `todo`, `inProgress`, `complete`.

## Response

- `property` (DatabaseProperty, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `rewritten` (integer, required)

```json
{
  "property": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "name": "Notes",
    "type": "title",
    "key": "string",
    "config": {
      "options": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "name": "Notes",
          "color": "default",
          "group": "todo"
        }
      ],
      "numberFormat": "number",
      "decimals": 0,
      "currency": "string",
      "includeTime": false,
      "range": false,
      "relation": {
        "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "twoWay": false,
        "reversePropertyId": null,
        "limit": "one"
      },
      "rollup": {
        "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "function": "showOriginal"
      },
      "expression": "string",
      "prefix": "string",
      "extra": {}
    },
    "sortKey": "a0",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "rewritten": 0
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete a select option

Source: https://developers.lydie.co/api/databases/delete-a-select-option

`DELETE /v1/database-properties/{propertyId}/options/{optionId}`

Removes the option and clears it from every row that uses it (one undo step).

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/options/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `propertyId` (ULID, required)
- `optionId` (ULID, required)

## Response

- `property` (DatabaseProperty, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `rewritten` (integer, required)

```json
{
  "property": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "name": "Notes",
    "type": "title",
    "key": "string",
    "config": {
      "options": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "name": "Notes",
          "color": "default",
          "group": "todo"
        }
      ],
      "numberFormat": "number",
      "decimals": 0,
      "currency": "string",
      "includeTime": false,
      "range": false,
      "relation": {
        "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "twoWay": false,
        "reversePropertyId": null,
        "limit": "one"
      },
      "rollup": {
        "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "function": "showOriginal"
      },
      "expression": "string",
      "prefix": "string",
      "extra": {}
    },
    "sortKey": "a0",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "rewritten": 0
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Reorder a select option

Source: https://developers.lydie.co/api/databases/reorder-a-select-option

`POST /v1/database-properties/{propertyId}/options/{optionId}/move`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-properties/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/options/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/move" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "index": 0
  }'
```

## Path parameters

- `propertyId` (ULID, required)
- `optionId` (ULID, required)

## Body

- `index` (integer, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Move a database row

Source: https://developers.lydie.co/api/databases/move-a-database-row

`POST /v1/database-rows/{rowId}/move`

Places a row after/before another (the manual order every unsorted view shows) and, with group/subGroup and a grouped viewId, moves it to that group by setting the grouped property.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-rows/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/move" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `rowId` (ULID, required)

## Body

- `viewId` (ULID, optional)
- `afterId` (ULID, optional)
- `beforeId` (ULID, optional)
- `group` (string, optional, nullable)
- `subGroup` (string, optional, nullable)
- `fromGroup` (string, optional, nullable): The group it was in (list-valued groups).
- `fromSubGroup` (string, optional, nullable)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Update a database view

Source: https://developers.lydie.co/api/databases/update-a-database-view

`PATCH /v1/database-views/{id}`

Changes the view's type and/or replaces the given top-level config fields (filter, sorts, groupBy, subGroupBy, columns, limit, summaries, layout); fields not given stay.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `type` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfigPatchInput, optional): Default: `{}`.
  - `filter` (FilterNode, optional, nullable)
  - `sorts` (object[], optional)
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupByInput, optional, nullable)
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumnInput[], optional)
    - `propertyId` (ULID, required)
    - `visible` (boolean, optional): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, optional, nullable): (≥ 1)
  - `summaries` (object, optional): propertyId → summary name
  - `layout` (ViewLayoutInput, optional)
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, optional)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete a database view

Source: https://developers.lydie.co/api/databases/delete-a-database-view

`DELETE /v1/database-views/{id}`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Duplicate a database view

Source: https://developers.lydie.co/api/databases/duplicate-a-database-view

`POST /v1/database-views/{id}/duplicate`

Copies a view right after itself. The name defaults to “<name> copy”.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/duplicate" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `newId` (ULID, optional)
- `name` (string, optional): (1–200 chars)
- `sortKey` (string, optional): (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Reorder a database view

Source: https://developers.lydie.co/api/databases/reorder-a-database-view

`POST /v1/database-views/{id}/move`

The first view opens by default (and is what a plain embed shows).

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/move" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Rename a database view

Source: https://developers.lydie.co/api/databases/rename-a-database-view

`POST /v1/database-views/{id}/rename`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rename" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes"
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `name` (string, required): (1–200 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a database view

Source: https://developers.lydie.co/api/databases/restore-a-database-view

`POST /v1/database-views/{id}/restore`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/database-views/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a database

Source: https://developers.lydie.co/api/databases/create-a-database

`POST /v1/databases`

Creates a database: a document whose children are its rows. With documentId, turns an existing document into a database (its children become rows). Starts with a title property and one view.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA"
  }'
```

## Body

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id of the new database document.
- `documentId` (ULID, optional): Turn this existing document into a database.
- `parentId` (ULID, optional, nullable): Default: `null`.
- `title` (string, optional): Default: `"Untitled database"`. (1–255 chars)
- `teamspaceId` (string, optional, nullable): Hosted: the teamspace a new top-level database goes into (null or absent: the creator's private section). Ignored with parentId or documentId, and in local mode. (1–64 chars)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)
- `viewType` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`. Default: `"table"`.
- `titlePropertyId` (ULID, optional)
- `viewId` (ULID, optional)

## Response

- `database` (Database, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `config` (DatabaseConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `templateIds` (ULID[], required): Default: `[]`.
    - `extra` (object, required): Default: `{}`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `properties` (DatabaseProperty[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `views` (DatabaseView[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `sorts` (object[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupBy, required, nullable): Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumn[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `visible` (boolean, required): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
    - `summaries` (object, required): propertyId → summary name Default: `{}`.
    - `layout` (ViewLayout, required): Default: `{}`.
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, required): Default: `{}`.
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "database": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "config": {
      "filter": null,
      "templateIds": [],
      "extra": {}
    },
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "properties": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "title",
      "key": "string",
      "config": {
        "options": [
          null
        ],
        "numberFormat": "number",
        "decimals": 0,
        "currency": "string",
        "includeTime": false,
        "range": false,
        "relation": {
          "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "twoWay": false,
          "reversePropertyId": null,
          "limit": "one"
        },
        "rollup": {
          "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "function": "showOriginal"
        },
        "expression": "string",
        "prefix": "string",
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ],
  "views": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "table",
      "config": {
        "filter": null,
        "sorts": [],
        "groupBy": null,
        "subGroupBy": null,
        "columns": [],
        "limit": null,
        "summaries": {},
        "layout": {},
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Add a database property

Source: https://developers.lydie.co/api/databases/add-a-database-property

`POST /v1/databases/{databaseId}/properties`

Adds a property. key defaults to the name (the frontmatter key in a folder). A two-way relation also adds the synced property on the related database (config.relation.reversePropertyId is its id). A uniqueId (config.prefix, e.g. LYD) numbers the existing rows in creation order; its key may not be "id".

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/properties" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes",
    "type": "title"
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `id` (ULID, optional)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, optional): (1–128 chars)
- `config` (PropertyConfigSpecInput, optional): Default: `{}`.
  - `options` (object[], optional): select, multiSelect, status
    - `id` (ULID, optional)
    - `name` (string, required): (1–200 chars)
    - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfigInput, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, optional): Default: `false`.
    - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfigInput, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `reverseName` (string, optional): Two-way relations. (1–200 chars)
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): Display name (Bases displayName). (1–200 chars)
- `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
- `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
- `config` (PropertyConfig, required)
  - `options` (SelectOption[], optional): select, multiSelect, status
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
    - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
  - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
  - `decimals` (integer, optional): (0–10)
  - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
  - `includeTime` (boolean, optional): date: values carry a time
  - `range` (boolean, optional): date: values may carry an end (start/end)
  - `relation` (RelationConfig, optional)
    - `databaseId` (ULID, required): The database whose rows this relation points at.
    - `twoWay` (boolean, required): Default: `false`.
    - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
    - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
  - `rollup` (RollupConfig, optional)
    - `relationPropertyId` (ULID, required)
    - `targetPropertyId` (ULID, required): A property of the related database.
    - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
  - `expression` (string, optional): formula: an Obsidian Bases expression
  - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
  - `extra` (object, optional)
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "title",
  "key": "string",
  "config": {
    "options": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "name": "Notes",
        "color": "default",
        "group": "todo"
      }
    ],
    "numberFormat": "number",
    "decimals": 0,
    "currency": "string",
    "includeTime": false,
    "range": false,
    "relation": {
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "twoWay": false,
      "reversePropertyId": null,
      "limit": "one"
    },
    "rollup": {
      "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "function": "showOriginal"
    },
    "expression": "string",
    "prefix": "string",
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Query a database

Source: https://developers.lydie.co/api/databases/query-a-database

`POST /v1/databases/{databaseId}/query`

Returns one window of a view's rows (filtered, sorted, grouped), with the total and group counts. Pass viewId for a saved view, or view for an ad-hoc one (both: view overrides). uniqueId values are numbers (shown as prefix-number, e.g. LYD-12); filters take 12 or "LYD-12".

Scope: `docs:read`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/query" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `viewId` (ULID, optional)
- `view` (object, optional)
  - `type` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`. Default: `"table"`.
  - `config` (ViewConfigPatchInput, optional): Default: `{}`.
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `window` (object, optional): Default: `{"offset":0,"limit":100}`.
  - `offset` (integer, optional): Default: `0`.
  - `limit` (integer, optional): Default: `100`. (0–1000)
  - `group` (string, optional, nullable)
  - `subGroup` (string, optional, nullable)
  - `range` (object, optional)
    - `propertyId` (ULID, optional): Default: the view's calendar property.
    - `start` (string, required): Inclusive, YYYY-MM-DD
    - `end` (string, required): Exclusive, YYYY-MM-DD
- `today` (string, optional): The caller's local date for relative date filters. Default: the server's.

## Response

- `total` (integer, required)
- `offset` (integer, required)
- `rows` (ViewRow[], required)
  - `id` (ULID, required)
  - `title` (string, required)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `createdBy` (string, required, nullable): (≥ 1 chars)
  - `updatedBy` (string, required, nullable): (≥ 1 chars)
  - `group` (string, required, nullable): The row's group (null: no value or not grouped).
  - `subGroup` (string, required, nullable)
  - `computed` (object, required)
- `groups` (ViewGroup[], required)
  - `key` (string, required, nullable)
  - `subKey` (string, required, nullable): Set for sub-groups (board swimlanes); null otherwise.
  - `count` (integer, required)
  - `start` (integer, required)

```json
{
  "total": 0,
  "offset": 0,
  "rows": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "title": "Meeting notes",
      "sortKey": "a0",
      "properties": {},
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "createdBy": null,
      "updatedBy": null,
      "group": null,
      "subGroup": null,
      "computed": {}
    }
  ],
  "groups": [
    {
      "key": null,
      "subKey": null,
      "count": 0,
      "start": 0
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a database row

Source: https://developers.lydie.co/api/databases/create-a-database-row

`POST /v1/databases/{databaseId}/rows`

Creates a row (a document under the database). Values implied by the view's filter and by the group (group/subGroup keys) are filled in, as in Notion; values override them. With templateId, the template's properties and body are copied first. uniqueId properties get the next number unless values gives one (12 or "LYD-12").

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `id` (ULID, optional)
- `title` (string, optional): Default: `"Untitled"`. (1–255 chars)
- `values` (object, optional): Default: `{}`.
- `viewId` (ULID, optional)
- `group` (string, optional, nullable)
- `subGroup` (string, optional, nullable)
- `templateId` (ULID, optional)
- `afterId` (ULID, optional)
- `beforeId` (ULID, optional)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `parentId` (ULID, required, nullable)
- `title` (string, required): (1–255 chars)
- `sortKey` (string, required): (1–256 chars)
- `properties` (object, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "parentId": null,
  "title": "Meeting notes",
  "sortKey": "a0",
  "properties": {
    "status": "draft"
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Set row values

Source: https://developers.lydie.co/api/databases/set-row-values

`PATCH /v1/databases/{databaseId}/rows`

Sets property values on one or many rows in one step: rowIds with set/unset applies the same values to every row; updates gives each row its own. Values are checked against the property type; unknown select options are added. Relation changes update the two-way side. uniqueId values are positive whole numbers: pass 12 or "LYD-12".

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `rowIds` (ULID[], optional): (≤ 10000 items)
- `set` (object, optional): Default: `{}`.
- `unset` (ULID[], optional): Default: `[]`.
- `updates` (object[], optional): (≤ 10000 items)
  - `rowId` (ULID, required)
  - `set` (object, optional): Default: `{}`.
  - `unset` (ULID[], optional): Default: `[]`.
- `exact` (boolean, optional): Write the values as given: no type checks, no new options, no two-way relation updates. Undo uses it to restore earlier values exactly. Default: `false`.
- `newOptions` (object, optional): Options this call adds (recorded by the client so replays mint the same ids).

## Response

- `updated` (ULID[], required)

```json
{
  "updated": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete database rows

Source: https://developers.lydie.co/api/databases/delete-database-rows

`POST /v1/databases/{databaseId}/rows/delete`

Moves rows to the trash (as doc.delete). Relations to them hide until restored.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows/delete" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rowIds": [
      "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
    ]
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `rowIds` (ULID[], required): (1–10000 items)

## Response

- `deletedIds` (ULID[], required)
- `deletedAt` (timestamp, required, nullable)

```json
{
  "deletedIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ],
  "deletedAt": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Duplicate database rows

Source: https://developers.lydie.co/api/databases/duplicate-database-rows

`POST /v1/databases/{databaseId}/rows/duplicate`

Copies rows (title, values and body), each right after its original.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows/duplicate" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rowIds": [
      "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
    ]
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `rowIds` (ULID[], required): (1–1000 items)
- `ids` (ULID[], optional): Client-minted ids for the copies, in order.

## Response

- `rows` (Document[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "rows": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "parentId": null,
      "title": "Meeting notes",
      "sortKey": "a0",
      "properties": {
        "status": "draft"
      },
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore database rows

Source: https://developers.lydie.co/api/databases/restore-database-rows

`POST /v1/databases/{databaseId}/rows/restore`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rowIds": [
      "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
    ]
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `rowIds` (ULID[], required): (1–10000 items)

## Response

- `restoredIds` (ULID[], required)

```json
{
  "restoredIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Write database rows

Source: https://developers.lydie.co/api/databases/write-database-rows

`POST /v1/databases/{databaseId}/rows/write`

Creates, updates and deletes rows in one step. A row without id is created; with id it is updated (title renames it); delete: true moves it to the trash. values are keyed by property id, frontmatter key or name; relation values are row ids; select values are option names (new names become options); uniqueId values are numbers (pass 12 or "LYD-12"; new rows get the next number). unset clears properties.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/rows/write" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rows": [
      {}
    ]
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `rows` (object[], required): (1–1000 items)
  - `id` (ULID, optional): An existing row to update or delete.
  - `title` (string, optional): (1–255 chars)
  - `values` (object, optional): Default: `{}`.
  - `unset` (string[], optional): Default: `[]`.
  - `delete` (boolean, optional): Default: `false`.

## Response

- `created` (ULID[], required)
- `updated` (ULID[], required)
- `deleted` (ULID[], required)

```json
{
  "created": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ],
  "updated": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ],
  "deleted": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a database's properties

Source: https://developers.lydie.co/api/databases/change-a-databases-properties

`POST /v1/databases/{databaseId}/schema`

Adds, changes and removes properties in one step. update can rename (name), change the type (values are converted), the frontmatter key or the config (options, relation, number format, formula expression). Removed properties keep their values in the rows.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/schema" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `add` (object[], optional): Default: `[]`.
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, optional): (1–128 chars)
  - `config` (PropertyConfigSpecInput, optional)
    - `options` (object[], optional): select, multiSelect, status
      - `id` (ULID, optional)
      - `name` (string, required): (1–200 chars)
      - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfigInput, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, optional): Default: `false`.
      - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfigInput, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
- `update` (object[], optional): Default: `[]`.
  - `property` (string, required): A property's id, frontmatter key or name (case-insensitive). (≥ 1 chars)
  - `name` (string, optional): (1–200 chars)
  - `type` (string, optional): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, optional): (1–128 chars)
  - `config` (PropertyConfigSpecInput, optional)
    - `options` (object[], optional): select, multiSelect, status
      - `id` (ULID, optional)
      - `name` (string, required): (1–200 chars)
      - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfigInput, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, optional): Default: `false`.
      - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfigInput, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
- `remove` (string[], optional): Default: `[]`.

## Response

- `id` (ULID, required)
- `properties` (object[], required)
  - `id` (ULID, required)
  - `name` (string, required)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required)
- `views` (object[], required)
  - `id` (ULID, required)
  - `name` (string, required)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "properties": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "title",
      "key": "string"
    }
  ],
  "views": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "table"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List row templates

Source: https://developers.lydie.co/api/databases/list-row-templates

`GET /v1/databases/{databaseId}/templates`

The database's row templates (config.templateIds), in order, live ones only. Templates are left out of views, counts and relation pickers; pass one as createRow's templateId.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/templates" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `databaseId` (ULID, required)

## Response

- `templates` (Document[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `parentId` (ULID, required, nullable)
  - `title` (string, required): (1–255 chars)
  - `sortKey` (string, required): (1–256 chars)
  - `properties` (object, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "templates": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "parentId": null,
      "title": "Meeting notes",
      "sortKey": "a0",
      "properties": {
        "status": "draft"
      },
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a database view

Source: https://developers.lydie.co/api/databases/create-a-database-view

`POST /v1/databases/{databaseId}/views`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/views" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes",
    "type": "table"
  }'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `id` (ULID, optional)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfigInput, optional): Default: `{"filter":null,"sorts":[],"groupBy":null,"subGroupBy":null,"columns":[],"limit":null,"summaries":{},"layout":{},"extra":{}}`.
  - `filter` (FilterNode, optional, nullable): Default: `null`.
  - `sorts` (object[], optional): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupByInput, optional, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumnInput[], optional): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, optional): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, optional, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, optional): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayoutInput, optional): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, optional): Default: `{}`.
- `afterId` (ULID, optional): Place directly after this sibling.
- `beforeId` (ULID, optional): Place directly before this sibling.
- `sortKey` (string, optional): Explicit fractional key (recorded so replays converge). (1–256 chars)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `databaseId` (ULID, required)
- `name` (string, required): (1–200 chars)
- `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
- `config` (ViewConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `sorts` (object[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
  - `groupBy` (GroupBy, required, nullable): Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
    - `propertyId` (ULID, required)
    - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `order` (string[], optional)
    - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
    - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
    - `collapsed` (string[], optional)
  - `columns` (ViewColumn[], required): Default: `[]`.
    - `propertyId` (ULID, required)
    - `visible` (boolean, required): Default: `true`.
    - `width` (integer, optional): (20–2000)
  - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
  - `summaries` (object, required): propertyId → summary name Default: `{}`.
  - `layout` (ViewLayout, required): Default: `{}`.
    - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
    - `wrapCells` (boolean, optional): table
    - `cardSize` (integer, optional): board, gallery: px (50–1000)
    - `cover` (object, optional, nullable): board, gallery: the card image
    - `coverFit` (string, optional): One of: `cover`, `contain`.
    - `coverAspectRatio` (number, optional): (0.1–10)
    - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
    - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
    - `calendarMode` (string, optional): One of: `month`, `week`.
    - `showWeekends` (boolean, optional)
    - `colorColumns` (boolean, optional): board
  - `extra` (object, required): Default: `{}`.
- `sortKey` (string, required): (1–256 chars)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "name": "Notes",
  "type": "table",
  "config": {
    "filter": null,
    "sorts": [],
    "groupBy": null,
    "subGroupBy": null,
    "columns": [],
    "limit": null,
    "summaries": {},
    "layout": {},
    "extra": {}
  },
  "sortKey": "a0",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a database's views

Source: https://developers.lydie.co/api/databases/change-a-databases-views

`POST /v1/databases/{databaseId}/views/change`

Adds, changes and removes views in one step. config is merged into the view's config (filter, sorts, groupBy, columns, …); see get_database for the current values.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/views/change" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `databaseId` (ULID, required)

## Body

- `add` (object[], optional): Default: `[]`.
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfigPatchInput, optional)
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `update` (object[], optional): Default: `[]`.
  - `view` (string, required): A view's id or name (case-insensitive). (≥ 1 chars)
  - `name` (string, optional): (1–200 chars)
  - `type` (string, optional): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfigPatchInput, optional)
    - `filter` (FilterNode, optional, nullable)
    - `sorts` (object[], optional)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupByInput, optional, nullable)
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes.
      - `propertyId` (ULID, required)
      - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumnInput[], optional)
      - `propertyId` (ULID, required)
      - `visible` (boolean, optional): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, optional, nullable): (≥ 1)
    - `summaries` (object, optional): propertyId → summary name
    - `layout` (ViewLayoutInput, optional)
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, optional)
- `remove` (string[], optional): Default: `[]`.

## Response

- `id` (ULID, required)
- `properties` (object[], required)
  - `id` (ULID, required)
  - `name` (string, required)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required)
- `views` (object[], required)
  - `id` (ULID, required)
  - `name` (string, required)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "properties": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "title",
      "key": "string"
    }
  ],
  "views": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "table"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a database

Source: https://developers.lydie.co/api/databases/get-a-database

`GET /v1/databases/{id}`

Returns a database's settings, live properties and views, in order.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `database` (Database, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `config` (DatabaseConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `templateIds` (ULID[], required): Default: `[]`.
    - `extra` (object, required): Default: `{}`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `properties` (DatabaseProperty[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `views` (DatabaseView[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `sorts` (object[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupBy, required, nullable): Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumn[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `visible` (boolean, required): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
    - `summaries` (object, required): propertyId → summary name Default: `{}`.
    - `layout` (ViewLayout, required): Default: `{}`.
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, required): Default: `{}`.
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "database": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "config": {
      "filter": null,
      "templateIds": [],
      "extra": {}
    },
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "properties": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "title",
      "key": "string",
      "config": {
        "options": [
          null
        ],
        "numberFormat": "number",
        "decimals": 0,
        "currency": "string",
        "includeTime": false,
        "range": false,
        "relation": {
          "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "twoWay": false,
          "reversePropertyId": null,
          "limit": "one"
        },
        "rollup": {
          "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "function": "showOriginal"
        },
        "expression": "string",
        "prefix": "string",
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ],
  "views": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "table",
      "config": {
        "filter": null,
        "sorts": [],
        "groupBy": null,
        "subGroupBy": null,
        "columns": [],
        "limit": null,
        "summaries": {},
        "layout": {},
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Update database settings

Source: https://developers.lydie.co/api/databases/update-database-settings

`PATCH /v1/databases/{id}`

Sets the filter applied to every view and the row templates.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `filter` (FilterNode, optional, nullable)
- `templateIds` (ULID[], optional)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `config` (DatabaseConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `templateIds` (ULID[], required): Default: `[]`.
  - `extra` (object, required): Default: `{}`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "config": {
    "filter": null,
    "templateIds": [],
    "extra": {}
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Turn a database back into a page

Source: https://developers.lydie.co/api/databases/turn-a-database-back-into-a-page

`DELETE /v1/databases/{id}`

Removes the database (schema and views go to the trash with it); the document and its rows stay as ordinary pages. To delete the document itself use doc.delete.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `config` (DatabaseConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `templateIds` (ULID[], required): Default: `[]`.
  - `extra` (object, required): Default: `{}`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "config": {
    "filter": null,
    "templateIds": [],
    "extra": {}
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Replace a database's schema and views

Source: https://developers.lydie.co/api/databases/replace-a-databases-schema-and-views

`PUT /v1/databases/{id}/definition`

Applies a whole definition (what fromBase reads from a .base file): properties and views with a known id are updated, new ones created, live ones missing from it deleted. Row values are not touched.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X PUT "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/definition" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "definition": {
      "config": {},
      "properties": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "name": "Notes",
          "type": "title",
          "key": "string"
        }
      ],
      "views": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "name": "Notes",
          "type": "table",
          "config": {}
        }
      ]
    }
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `definition` (object, required)
  - `config` (DatabaseConfigInput, required)
    - `filter` (FilterNode, optional, nullable): Default: `null`.
    - `templateIds` (ULID[], optional): Default: `[]`.
    - `extra` (object, optional): Default: `{}`.
  - `properties` (object[], required)
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
    - `key` (string, required): (1–128 chars)
    - `config` (PropertyConfigInput, optional): Default: `{}`.
      - `options` (SelectOptionInput[], optional): select, multiSelect, status
        - `id` (ULID, required)
        - `name` (string, required): (1–200 chars)
        - `color` (string, optional): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
        - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
      - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
      - `decimals` (integer, optional): (0–10)
      - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
      - `includeTime` (boolean, optional): date: values carry a time
      - `range` (boolean, optional): date: values may carry an end (start/end)
      - `relation` (RelationConfigInput, optional)
        - `databaseId` (ULID, required): The database whose rows this relation points at.
        - `twoWay` (boolean, optional): Default: `false`.
        - `reversePropertyId` (ULID, optional, nullable): The synced property on the other database (two-way relations). Default: `null`.
        - `limit` (string, optional): One of: `one`, `many`. Default: `"many"`.
      - `rollup` (RollupConfigInput, optional)
        - `relationPropertyId` (ULID, required)
        - `targetPropertyId` (ULID, required): A property of the related database.
        - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
      - `expression` (string, optional): formula: an Obsidian Bases expression
      - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
      - `extra` (object, optional)
  - `views` (object[], required)
    - `id` (ULID, required)
    - `name` (string, required): (1–200 chars)
    - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
    - `config` (ViewConfigInput, required)
      - `filter` (FilterNode, optional, nullable): Default: `null`.
      - `sorts` (object[], optional): Default: `[]`.
        - `propertyId` (ULID, required)
        - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
      - `groupBy` (GroupByInput, optional, nullable): Default: `null`.
        - `propertyId` (ULID, required)
        - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
        - `order` (string[], optional)
        - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
        - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
        - `collapsed` (string[], optional)
      - `subGroupBy` (GroupByInput, optional, nullable): Board swimlanes. Default: `null`.
        - `propertyId` (ULID, required)
        - `direction` (string, optional): One of: `asc`, `desc`. Default: `"asc"`.
        - `order` (string[], optional)
        - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
        - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
        - `collapsed` (string[], optional)
      - `columns` (ViewColumnInput[], optional): Default: `[]`.
        - `propertyId` (ULID, required)
        - `visible` (boolean, optional): Default: `true`.
        - `width` (integer, optional): (20–2000)
      - `limit` (integer, optional, nullable): Default: `null`. (≥ 1)
      - `summaries` (object, optional): propertyId → summary name Default: `{}`.
      - `layout` (ViewLayoutInput, optional): Default: `{}`.
        - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
        - `wrapCells` (boolean, optional): table
        - `cardSize` (integer, optional): board, gallery: px (50–1000)
        - `cover` (object, optional, nullable): board, gallery: the card image
        - `coverFit` (string, optional): One of: `cover`, `contain`.
        - `coverAspectRatio` (number, optional): (0.1–10)
        - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
        - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
        - `calendarMode` (string, optional): One of: `month`, `week`.
        - `showWeekends` (boolean, optional)
        - `colorColumns` (boolean, optional): board
      - `extra` (object, optional): Default: `{}`.

## Response

- `database` (Database, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `config` (DatabaseConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `templateIds` (ULID[], required): Default: `[]`.
    - `extra` (object, required): Default: `{}`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `properties` (DatabaseProperty[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): Display name (Bases displayName). (1–200 chars)
  - `type` (string, required): One of: `title`, `text`, `number`, `select`, `multiSelect`, `status`, `date`, `checkbox`, `url`, `email`, `phone`, `person`, `files`, `relation`, `rollup`, `formula`, `uniqueId`, `createdTime`, `updatedTime`, `createdBy`, `updatedBy`.
  - `key` (string, required): Stored types: the frontmatter key holding the value. Formulas, rollups, createdBy and updatedBy: the formula name in the .base file. Unused for title and created/updated time. (1–128 chars)
  - `config` (PropertyConfig, required)
    - `options` (SelectOption[], optional): select, multiSelect, status
      - `id` (ULID, required)
      - `name` (string, required): (1–200 chars)
      - `color` (string, required): One of: `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`. Default: `"default"`.
      - `group` (string, optional): One of: `todo`, `inProgress`, `complete`.
    - `numberFormat` (string, optional): One of: `number`, `integer`, `commas`, `percent`, `currency`.
    - `decimals` (integer, optional): (0–10)
    - `currency` (string, optional): ISO 4217 code, with numberFormat currency (3–3 chars)
    - `includeTime` (boolean, optional): date: values carry a time
    - `range` (boolean, optional): date: values may carry an end (start/end)
    - `relation` (RelationConfig, optional)
      - `databaseId` (ULID, required): The database whose rows this relation points at.
      - `twoWay` (boolean, required): Default: `false`.
      - `reversePropertyId` (ULID, required, nullable): The synced property on the other database (two-way relations). Default: `null`.
      - `limit` (string, required): One of: `one`, `many`. Default: `"many"`.
    - `rollup` (RollupConfig, optional)
      - `relationPropertyId` (ULID, required)
      - `targetPropertyId` (ULID, required): A property of the related database.
      - `function` (string, required): One of: `showOriginal`, `showUnique`, `count`, `countValues`, `countUnique`, `countEmpty`, `countNotEmpty`, `percentEmpty`, `percentNotEmpty`, `sum`, `average`, `median`, `min`, `max`, `range`, `earliest`, `latest`, `checked`, `unchecked`, `percentChecked`, `percentUnchecked`.
    - `expression` (string, optional): formula: an Obsidian Bases expression
    - `prefix` (string, optional): uniqueId: shown before the number ("LYD" → LYD-12) (≤ 16 chars)
    - `extra` (object, optional)
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
- `views` (DatabaseView[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `databaseId` (ULID, required)
  - `name` (string, required): (1–200 chars)
  - `type` (string, required): One of: `table`, `board`, `list`, `calendar`, `gallery`.
  - `config` (ViewConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `sorts` (object[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
    - `groupBy` (GroupBy, required, nullable): Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `subGroupBy` (GroupBy, required, nullable): Board swimlanes. Default: `null`.
      - `propertyId` (ULID, required)
      - `direction` (string, required): One of: `asc`, `desc`. Default: `"asc"`.
      - `order` (string[], optional)
      - `hideEmpty` (boolean, optional): Hide groups with no rows (board columns).
      - `dateBucket` (string, optional): Date grouping; default month. One of: `day`, `week`, `month`, `year`.
      - `collapsed` (string[], optional)
    - `columns` (ViewColumn[], required): Default: `[]`.
      - `propertyId` (ULID, required)
      - `visible` (boolean, required): Default: `true`.
      - `width` (integer, optional): (20–2000)
    - `limit` (integer, required, nullable): Default: `null`. (≥ 1)
    - `summaries` (object, required): propertyId → summary name Default: `{}`.
    - `layout` (ViewLayout, required): Default: `{}`.
      - `rowHeight` (string, optional): table One of: `short`, `medium`, `tall`, `extra`.
      - `wrapCells` (boolean, optional): table
      - `cardSize` (integer, optional): board, gallery: px (50–1000)
      - `cover` (object, optional, nullable): board, gallery: the card image
      - `coverFit` (string, optional): One of: `cover`, `contain`.
      - `coverAspectRatio` (number, optional): (0.1–10)
      - `markers` (string, optional): list One of: `bullet`, `number`, `none`.
      - `calendarPropertyId` (ULID, optional): calendar: the date property placing rows
      - `calendarMode` (string, optional): One of: `month`, `week`.
      - `showWeekends` (boolean, optional)
      - `colorColumns` (boolean, optional): board
    - `extra` (object, required): Default: `{}`.
  - `sortKey` (string, required): (1–256 chars)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "database": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "config": {
      "filter": null,
      "templateIds": [],
      "extra": {}
    },
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z",
    "deletedAt": null,
    "createdBy": null,
    "updatedBy": null
  },
  "properties": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "title",
      "key": "string",
      "config": {
        "options": [
          null
        ],
        "numberFormat": "number",
        "decimals": 0,
        "currency": "string",
        "includeTime": false,
        "range": false,
        "relation": {
          "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "twoWay": false,
          "reversePropertyId": null,
          "limit": "one"
        },
        "rollup": {
          "relationPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "targetPropertyId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "function": "showOriginal"
        },
        "expression": "string",
        "prefix": "string",
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ],
  "views": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "databaseId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "name": "Notes",
      "type": "table",
      "config": {
        "filter": null,
        "sorts": [],
        "groupBy": null,
        "subGroupBy": null,
        "columns": [],
        "limit": null,
        "summaries": {},
        "layout": {},
        "extra": {}
      },
      "sortKey": "a0",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a database

Source: https://developers.lydie.co/api/databases/restore-a-database

`POST /v1/databases/{id}/restore`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/databases/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `config` (DatabaseConfig, required)
  - `filter` (FilterNode, required, nullable): Default: `null`.
  - `templateIds` (ULID[], required): Default: `[]`.
  - `extra` (object, required): Default: `{}`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "config": {
    "filter": null,
    "templateIds": [],
    "extra": {}
  },
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List databases

Source: https://developers.lydie.co/api/databases/list-databases

`GET /v1/workspaces/{workspaceId}/databases`

Lists the live databases of a workspace (database documents not in the trash).

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/databases" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `databases` (DatabaseSummary[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `config` (DatabaseConfig, required)
    - `filter` (FilterNode, required, nullable): Default: `null`.
    - `templateIds` (ULID[], required): Default: `[]`.
    - `extra` (object, required): Default: `{}`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)
  - `title` (string, required)
  - `parentId` (ULID, required, nullable)

```json
{
  "databases": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "config": {
        "filter": null,
        "templateIds": [],
        "extra": {}
      },
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null,
      "title": "Meeting notes",
      "parentId": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Attachments

Source: https://developers.lydie.co/api/attachments

Files attached to a workspace or a document, stored by their SHA-256 hash. Upload the bytes first, then record the attachment.

## Endpoints

- [Add an attachment](https://developers.lydie.co/api/attachments/add-an-attachment.md): `POST /v1/attachments`
- [Get an upload URL for a file](https://developers.lydie.co/api/attachments/get-an-upload-url-for-a-file.md): `POST /v1/attachments/uploads`
- [Get an attachment](https://developers.lydie.co/api/attachments/get-an-attachment.md): `GET /v1/attachments/{id}`
- [Delete an attachment](https://developers.lydie.co/api/attachments/delete-an-attachment.md): `DELETE /v1/attachments/{id}`
- [Get a download URL for an attachment](https://developers.lydie.co/api/attachments/get-a-download-url-for-an-attachment.md): `GET /v1/attachments/{id}/download-url`
- [Permanently delete an attachment](https://developers.lydie.co/api/attachments/permanently-delete-an-attachment.md): `POST /v1/attachments/{id}/purge`
- [Restore an attachment](https://developers.lydie.co/api/attachments/restore-an-attachment.md): `POST /v1/attachments/{id}/restore`
- [List attachments](https://developers.lydie.co/api/attachments/list-attachments.md): `GET /v1/workspaces/{workspaceId}/attachments`

## The Attachment object

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "documentId": null,
  "filename": "string",
  "contentType": "string",
  "size": 0,
  "sha256": "string",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

---

# Add an attachment

Source: https://developers.lydie.co/api/attachments/add-an-attachment

`POST /v1/attachments`

Records an attachment whose bytes are already stored under their SHA-256 (the Blob port locally, an upload URL when hosted). Several attachments may share the same bytes.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/attachments" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "filename": "string",
    "contentType": "string",
    "size": 0,
    "sha256": "string"
  }'
```

## Body

- `workspaceId` (string, required): (1–64 chars)
- `id` (ULID, optional): Client-minted id. Generated when omitted.
- `documentId` (ULID, optional, nullable): Default: `null`.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "documentId": null,
  "filename": "string",
  "contentType": "string",
  "size": 0,
  "sha256": "string",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get an upload URL for a file

Source: https://developers.lydie.co/api/attachments/get-an-upload-url-for-a-file

`POST /v1/attachments/uploads`

Checks access and limits and returns a signed URL (15 minutes) to PUT the file's bytes to. `upload` is null when the same bytes are already stored. Then record the file with attachment.create. Needs edit access to the document (or membership for workspace files).

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/attachments/uploads" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "contentType": "string",
    "size": 0,
    "sha256": "string"
  }'
```

## Body

- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, optional, nullable): Default: `null`.
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)

## Response

- `upload` (BlobUpload, required, nullable)
  - `method` ("PUT", required)
  - `url` (string, required)
  - `headers` (object, required)
  - `expiresAt` (timestamp, required)
- `maxBytes` (integer, required)

```json
{
  "upload": null,
  "maxBytes": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get an attachment

Source: https://developers.lydie.co/api/attachments/get-an-attachment

`GET /v1/attachments/{id}`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/attachments/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "documentId": null,
  "filename": "string",
  "contentType": "string",
  "size": 0,
  "sha256": "string",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete an attachment

Source: https://developers.lydie.co/api/attachments/delete-an-attachment

`DELETE /v1/attachments/{id}`

Moves an attachment to the trash. Restore it with attachment.restore.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/attachments/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "documentId": null,
  "filename": "string",
  "contentType": "string",
  "size": 0,
  "sha256": "string",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a download URL for an attachment

Source: https://developers.lydie.co/api/attachments/get-a-download-url-for-an-attachment

`GET /v1/attachments/{id}/download-url`

A signed URL valid for an hour, usable without a session (e.g. in <img src>).

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/attachments/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/download-url" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `url` (string, required)
- `expiresAt` (timestamp, required)

```json
{
  "url": "string",
  "expiresAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Permanently delete an attachment

Source: https://developers.lydie.co/api/attachments/permanently-delete-an-attachment

`POST /v1/attachments/{id}/purge`

Permanently deletes an attachment in the trash. Its bytes are removed when no other attachment uses them. Cannot be undone.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/attachments/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/purge" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `purgedIds` (ULID[], required)

```json
{
  "purgedIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore an attachment

Source: https://developers.lydie.co/api/attachments/restore-an-attachment

`POST /v1/attachments/{id}/restore`

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/attachments/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
- `filename` (string, required): (1–255 chars)
- `contentType` (string, required): (1–255 chars)
- `size` (integer, required)
- `sha256` (string, required)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, required, nullable)
- `createdBy` (string, optional, nullable): (≥ 1 chars)
- `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "documentId": null,
  "filename": "string",
  "contentType": "string",
  "size": 0,
  "sha256": "string",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null,
  "createdBy": null,
  "updatedBy": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List attachments

Source: https://developers.lydie.co/api/attachments/list-attachments

`GET /v1/workspaces/{workspaceId}/attachments`

Lists a workspace's attachments, or one document's, newest first.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/attachments" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `documentId` (ULID, optional)
- `includeDeleted` (boolean, optional): Default: `false`.

## Response

- `attachments` (Attachment[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `documentId` (ULID, required, nullable): The document it belongs to; null for workspace files.
  - `filename` (string, required): (1–255 chars)
  - `contentType` (string, required): (1–255 chars)
  - `size` (integer, required)
  - `sha256` (string, required)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, required, nullable)
  - `createdBy` (string, optional, nullable): (≥ 1 chars)
  - `updatedBy` (string, optional, nullable): (≥ 1 chars)

```json
{
  "attachments": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "documentId": null,
      "filename": "string",
      "contentType": "string",
      "size": 0,
      "sha256": "string",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Trash

Source: https://developers.lydie.co/api/trash

Deleted documents and attachments stay in the trash until they are restored or purged.

## Endpoints

- [List the trash](https://developers.lydie.co/api/trash/list-the-trash.md): `GET /v1/workspaces/{workspaceId}/trash`
- [Empty the trash](https://developers.lydie.co/api/trash/empty-the-trash.md): `DELETE /v1/workspaces/{workspaceId}/trash`

## The TrashItem object

- `kind` (string, required): One of: `document`, `attachment`.
- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `title` (string, required): Document title or attachment filename.
- `parentId` (ULID, required, nullable): Where a document goes back to on restore, if still there.
- `deletedAt` (timestamp, required)
- `deletedBy` (string, required, nullable): (≥ 1 chars)
- `descendantCount` (integer, required): Documents trashed together with it.

```json
{
  "kind": "document",
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "title": "Meeting notes",
  "parentId": null,
  "deletedAt": "2026-11-12T09:30:00.000Z",
  "deletedBy": null,
  "descendantCount": 0
}
```

---

# List the trash

Source: https://developers.lydie.co/api/trash/list-the-trash

`GET /v1/workspaces/{workspaceId}/trash`

Lists what is in a workspace's trash, newest first. A document deleted with its subtree is one item; restoring it restores the subtree.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/trash" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `limit` (integer, optional): Default: `100`. (1–500)

## Response

- `items` (TrashItem[], required)
  - `kind` (string, required): One of: `document`, `attachment`.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `title` (string, required): Document title or attachment filename.
  - `parentId` (ULID, required, nullable): Where a document goes back to on restore, if still there.
  - `deletedAt` (timestamp, required)
  - `deletedBy` (string, required, nullable): (≥ 1 chars)
  - `descendantCount` (integer, required): Documents trashed together with it.

```json
{
  "items": [
    {
      "kind": "document",
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "title": "Meeting notes",
      "parentId": null,
      "deletedAt": "2026-11-12T09:30:00.000Z",
      "deletedBy": null,
      "descendantCount": 0
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Empty the trash

Source: https://developers.lydie.co/api/trash/empty-the-trash

`DELETE /v1/workspaces/{workspaceId}/trash`

Permanently deletes everything in a workspace's trash. Cannot be undone.

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/trash" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `purgedIds` (ULID[], required)

```json
{
  "purgedIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# History

Source: https://developers.lydie.co/api/history

Sessions group the changes an agent made, so they can be reviewed and undone together.

## Endpoints

- [List agent sessions](https://developers.lydie.co/api/history/list-agent-sessions.md): `GET /v1/history/sessions`
- [List a session's changes](https://developers.lydie.co/api/history/list-a-sessions-changes.md): `GET /v1/history/sessions/{sessionId}`
- [Undo a session](https://developers.lydie.co/api/history/undo-a-session.md): `POST /v1/history/sessions/{sessionId}/undo`

## The HistorySession object

- `sessionId` (string, required)
- `actor` (Actor, required)
- `workspaceId` (string, required, nullable): (1–64 chars)
- `firstAt` (timestamp, required)
- `lastAt` (timestamp, required)
- `count` (integer, required)
- `undoneCount` (integer, required)

```json
{
  "sessionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "actor": {
    "type": "user",
    "id": "string"
  },
  "workspaceId": null,
  "firstAt": "2026-11-12T09:30:00.000Z",
  "lastAt": "2026-11-12T09:30:00.000Z",
  "count": 0,
  "undoneCount": 0
}
```

---

# List agent sessions

Source: https://developers.lydie.co/api/history/list-agent-sessions

`GET /v1/history/sessions`

Lists sessions that changed a workspace, most recent first.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/history/sessions" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Query parameters

- `workspaceId` (string, optional): (1–64 chars)
- `limit` (integer, optional): Default: `50`. (1–200)

## Response

- `sessions` (HistorySession[], required)
  - `sessionId` (string, required)
  - `actor` (Actor, required)
  - `workspaceId` (string, required, nullable): (1–64 chars)
  - `firstAt` (timestamp, required)
  - `lastAt` (timestamp, required)
  - `count` (integer, required)
  - `undoneCount` (integer, required)

```json
{
  "sessions": [
    {
      "sessionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "actor": {
        "type": "user",
        "id": null
      },
      "workspaceId": null,
      "firstAt": "2026-11-12T09:30:00.000Z",
      "lastAt": "2026-11-12T09:30:00.000Z",
      "count": 0,
      "undoneCount": 0
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List a session's changes

Source: https://developers.lydie.co/api/history/list-a-sessions-changes

`GET /v1/history/sessions/{sessionId}`

Lists every operation a session applied, oldest first.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/history/sessions/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `sessionId` (string, required): (≥ 1 chars)

## Query parameters

- `limit` (integer, optional): Default: `200`. (1–1000)

## Response

- `entries` (HistoryEntry[], required)
  - `id` (ULID, required)
  - `operation` (string, required)
  - `input` (any, required)
  - `inverse` (InverseStep[], required, nullable): Operations that undo it, in the order to run them; null if it cannot be undone.
    - `op` (string, required)
    - `input` (any, required)
    - `rewrite` (SchemaRewrite, optional)
      - `databaseId` (ULID, required)
      - `propertyId` (ULID, required)
      - `reason` (string, required): One of: `option`, `key`, `type`, `relation`, `uniqueId`.
  - `actor` (Actor, required)
  - `sessionId` (string, required, nullable)
  - `groupId` (ULID, required): Operations applied together (one transaction) share a group.
  - `workspaceId` (string, required, nullable): (1–64 chars)
  - `createdAt` (timestamp, required)
  - `undoneAt` (timestamp, required, nullable)

```json
{
  "entries": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "operation": "string",
      "input": "string",
      "inverse": null,
      "actor": {
        "type": "user",
        "id": null
      },
      "sessionId": null,
      "groupId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": null,
      "createdAt": "2026-11-12T09:30:00.000Z",
      "undoneAt": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Undo a session

Source: https://developers.lydie.co/api/history/undo-a-session

`POST /v1/history/sessions/{sessionId}/undo`

Reverts every change a session made, newest first, as one undoable step. Changes that later edits by others touched are skipped and reported, as are changes that cannot be undone.

Scope: `docs:write`. Undoable.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/history/sessions/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/undo" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `sessionId` (string, required): (≥ 1 chars)

## Response

- `undoneIds` (ULID[], required): History entries that were reverted.
- `skipped` (object[], required)
  - `id` (ULID, required)
  - `operation` (string, required)
  - `reason` (string, required): One of: `not_undoable`, `conflict`, `failed`.
  - `message` (string, required)

```json
{
  "undoneIds": [
    "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  ],
  "skipped": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "operation": "string",
      "reason": "not_undoable",
      "message": "string"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Workspaces

Source: https://developers.lydie.co/api/workspaces

A workspace holds documents, members and teamspaces. An API token belongs to exactly one.

## Endpoints

- [List your workspaces](https://developers.lydie.co/api/workspaces/list-your-workspaces.md): `GET /v1/workspaces`
- [Create a workspace](https://developers.lydie.co/api/workspaces/create-a-workspace.md): `POST /v1/workspaces`
- [Rename a workspace](https://developers.lydie.co/api/workspaces/rename-a-workspace.md): `PATCH /v1/workspaces/{workspaceId}`
- [Transfer workspace ownership](https://developers.lydie.co/api/workspaces/transfer-workspace-ownership.md): `POST /v1/workspaces/{workspaceId}/transfer-ownership`

## The WorkspaceSummary object

- `id` (string, required): (1–64 chars)
- `name` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)

```json
{
  "id": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "role": "owner",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z"
}
```

---

# List your workspaces

Source: https://developers.lydie.co/api/workspaces/list-your-workspaces

`GET /v1/workspaces`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Response

- `workspaces` (WorkspaceSummary[], required)
  - `id` (string, required): (1–64 chars)
  - `name` (string, required)
  - `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "workspaces": [
    {
      "id": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "name": "Notes",
      "role": "owner",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a workspace

Source: https://developers.lydie.co/api/workspaces/create-a-workspace

`POST /v1/workspaces`

Creates a workspace with you as its owner and an open, default teamspace called General.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes"
  }'
```

## Body

- `id` (string, optional): Client-minted id. Generated when omitted. (1–64 chars)
- `name` (string, required): (1–200 chars)
- `defaultTeamspaceId` (string, optional): (1–64 chars)

## Response

- `id` (string, required): (1–64 chars)
- `name` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)

```json
{
  "id": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "role": "owner",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Rename a workspace

Source: https://developers.lydie.co/api/workspaces/rename-a-workspace

`PATCH /v1/workspaces/{workspaceId}`

Scope: `docs:write`.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `name` (string, required): (1–200 chars)

## Response

- `id` (string, required): (1–64 chars)
- `name` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)

```json
{
  "id": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "role": "owner",
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Transfer workspace ownership

Source: https://developers.lydie.co/api/workspaces/transfer-workspace-ownership

`POST /v1/workspaces/{workspaceId}/transfer-ownership`

Makes another member (not a guest) the owner. You become an admin.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/transfer-ownership" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "kG7qL2m9XzP4tR8w"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `userId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Members

Source: https://developers.lydie.co/api/members

People in a workspace and their roles: owner, admin, member or guest.

## Endpoints

- [Leave a workspace](https://developers.lydie.co/api/members/leave-a-workspace.md): `POST /v1/workspaces/{workspaceId}/leave`
- [List workspace members](https://developers.lydie.co/api/members/list-workspace-members.md): `GET /v1/workspaces/{workspaceId}/members`
- [Remove a member](https://developers.lydie.co/api/members/remove-a-member.md): `DELETE /v1/workspaces/{workspaceId}/members/{userId}`
- [Change a member's role](https://developers.lydie.co/api/members/change-a-members-role.md): `POST /v1/workspaces/{workspaceId}/members/{userId}/role`

## The Member object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `userId` (string, required): (1–64 chars)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `name` (string, required)
- `email` (string, required)
- `image` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "userId": "kG7qL2m9XzP4tR8w",
  "role": "owner",
  "name": "Notes",
  "email": "ada@example.com",
  "image": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

---

# Leave a workspace

Source: https://developers.lydie.co/api/members/leave-a-workspace

`POST /v1/workspaces/{workspaceId}/leave`

Same as being removed. The owner must transfer ownership first. Your private pages go to the owner.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/leave" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List workspace members

Source: https://developers.lydie.co/api/members/list-workspace-members

`GET /v1/workspaces/{workspaceId}/members`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/members" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `members` (Member[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `userId` (string, required): (1–64 chars)
  - `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
  - `name` (string, required)
  - `email` (string, required)
  - `image` (string, required, nullable)
  - `createdAt` (timestamp, required)

```json
{
  "members": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "userId": "kG7qL2m9XzP4tR8w",
      "role": "owner",
      "name": "Notes",
      "email": "ada@example.com",
      "image": null,
      "createdAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Remove a member

Source: https://developers.lydie.co/api/members/remove-a-member

`DELETE /v1/workspaces/{workspaceId}/members/{userId}`

Removes someone from the workspace, its teamspaces and every page shared with them. Their private pages are transferred to the workspace owner and stay private.

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/members/kG7qL2m9XzP4tR8w" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)
- `userId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a member's role

Source: https://developers.lydie.co/api/members/change-a-members-role

`POST /v1/workspaces/{workspaceId}/members/{userId}/role`

Owners and admins can change roles. Only the owner can demote an admin. Making someone a guest removes them from every teamspace; they keep pages shared with them directly.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/members/kG7qL2m9XzP4tR8w/role" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)
- `userId` (string, required): (1–64 chars)

## Body

- `role` (string, required): One of: `admin`, `member`, `guest`.

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `userId` (string, required): (1–64 chars)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `name` (string, required)
- `email` (string, required)
- `image` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "userId": "kG7qL2m9XzP4tR8w",
  "role": "owner",
  "name": "Notes",
  "email": "ada@example.com",
  "image": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Teamspaces

Source: https://developers.lydie.co/api/teamspaces

Groups of pages with their own members. Open teamspaces are visible to every member; closed and private ones are not.

## Endpoints

- [Update a teamspace](https://developers.lydie.co/api/teamspaces/update-a-teamspace.md): `PATCH /v1/teamspaces/{teamspaceId}`
- [Delete a teamspace](https://developers.lydie.co/api/teamspaces/delete-a-teamspace.md): `DELETE /v1/teamspaces/{teamspaceId}`
- [Join an open teamspace](https://developers.lydie.co/api/teamspaces/join-an-open-teamspace.md): `POST /v1/teamspaces/{teamspaceId}/join`
- [Leave a teamspace](https://developers.lydie.co/api/teamspaces/leave-a-teamspace.md): `POST /v1/teamspaces/{teamspaceId}/leave`
- [List teamspace members](https://developers.lydie.co/api/teamspaces/list-teamspace-members.md): `GET /v1/teamspaces/{teamspaceId}/members`
- [Add someone to a teamspace](https://developers.lydie.co/api/teamspaces/add-someone-to-a-teamspace.md): `POST /v1/teamspaces/{teamspaceId}/members`
- [Remove someone from a teamspace](https://developers.lydie.co/api/teamspaces/remove-someone-from-a-teamspace.md): `DELETE /v1/teamspaces/{teamspaceId}/members/{userId}`
- [Change a teamspace member's role](https://developers.lydie.co/api/teamspaces/change-a-teamspace-members-role.md): `POST /v1/teamspaces/{teamspaceId}/members/{userId}/role`
- [Restore a deleted teamspace](https://developers.lydie.co/api/teamspaces/restore-a-deleted-teamspace.md): `POST /v1/teamspaces/{teamspaceId}/restore`
- [List teamspaces](https://developers.lydie.co/api/teamspaces/list-teamspaces.md): `GET /v1/workspaces/{workspaceId}/teamspaces`
- [Create a teamspace](https://developers.lydie.co/api/teamspaces/create-a-teamspace.md): `POST /v1/workspaces/{workspaceId}/teamspaces`

## The Teamspace object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `name` (string, required)
- `description` (string, required)
- `icon` (string, required, nullable)
- `visibility` (string, required): One of: `open`, `closed`, `private`.
- `isDefault` (boolean, required)
- `myRole` (string, required, nullable): One of: `owner`, `member`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, optional, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "description": "string",
  "icon": null,
  "visibility": "open",
  "isDefault": false,
  "myRole": null,
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null
}
```

---

# Update a teamspace

Source: https://developers.lydie.co/api/teamspaces/update-a-teamspace

`PATCH /v1/teamspaces/{teamspaceId}`

Changes name, description, icon, visibility or default flag. Teamspace owners and workspace owners/admins only. Changing visibility changes who can read its pages.

Scope: `docs:write`.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Body

- `name` (string, optional): (1–100 chars)
- `description` (string, optional): (≤ 2000 chars)
- `icon` (string, optional, nullable): (≤ 100 chars)
- `visibility` (string, optional): One of: `open`, `closed`, `private`.
- `isDefault` (boolean, optional)

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `name` (string, required)
- `description` (string, required)
- `icon` (string, required, nullable)
- `visibility` (string, required): One of: `open`, `closed`, `private`.
- `isDefault` (boolean, required)
- `myRole` (string, required, nullable): One of: `owner`, `member`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, optional, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "description": "string",
  "icon": null,
  "visibility": "open",
  "isDefault": false,
  "myRole": null,
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Delete a teamspace

Source: https://developers.lydie.co/api/teamspaces/delete-a-teamspace

`DELETE /v1/teamspaces/{teamspaceId}`

Soft-deletes the teamspace and moves its pages to the trash.

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Join an open teamspace

Source: https://developers.lydie.co/api/teamspaces/join-an-open-teamspace

`POST /v1/teamspaces/{teamspaceId}/join`

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/join" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Leave a teamspace

Source: https://developers.lydie.co/api/teamspaces/leave-a-teamspace

`POST /v1/teamspaces/{teamspaceId}/leave`

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/leave" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List teamspace members

Source: https://developers.lydie.co/api/teamspaces/list-teamspace-members

`GET /v1/teamspaces/{teamspaceId}/members`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/members" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Response

- `members` (TeamspaceMember[], required)
  - `id` (string, required): (1–64 chars)
  - `teamspaceId` (string, required): (1–64 chars)
  - `userId` (string, required): (1–64 chars)
  - `role` (string, required): One of: `owner`, `member`.
  - `name` (string, required)
  - `email` (string, required)

```json
{
  "members": [
    {
      "id": "string",
      "teamspaceId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "userId": "kG7qL2m9XzP4tR8w",
      "role": "owner",
      "name": "Notes",
      "email": "ada@example.com"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Add someone to a teamspace

Source: https://developers.lydie.co/api/teamspaces/add-someone-to-a-teamspace

`POST /v1/teamspaces/{teamspaceId}/members`

Teamspace owners and workspace owners/admins. Guests cannot join teamspaces.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/members" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "kG7qL2m9XzP4tR8w"
  }'
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Body

- `userId` (string, required): (1–64 chars)
- `role` (string, optional): One of: `owner`, `member`. Default: `"member"`.

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Remove someone from a teamspace

Source: https://developers.lydie.co/api/teamspaces/remove-someone-from-a-teamspace

`DELETE /v1/teamspaces/{teamspaceId}/members/{userId}`

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/members/kG7qL2m9XzP4tR8w" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)
- `userId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a teamspace member's role

Source: https://developers.lydie.co/api/teamspaces/change-a-teamspace-members-role

`POST /v1/teamspaces/{teamspaceId}/members/{userId}/role`

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/members/kG7qL2m9XzP4tR8w/role" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "owner"
  }'
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)
- `userId` (string, required): (1–64 chars)

## Body

- `role` (string, required): One of: `owner`, `member`.

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restore a deleted teamspace

Source: https://developers.lydie.co/api/teamspaces/restore-a-deleted-teamspace

`POST /v1/teamspaces/{teamspaceId}/restore`

Brings back a deleted teamspace and the pages that were moved to the trash with it. Pages trashed before the teamspace was deleted stay in the trash. Workspace owners and admins, and the teamspace's owners.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/teamspaces/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restore" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `teamspaceId` (string, required): Teamspace id. (1–64 chars)

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `name` (string, required)
- `description` (string, required)
- `icon` (string, required, nullable)
- `visibility` (string, required): One of: `open`, `closed`, `private`.
- `isDefault` (boolean, required)
- `myRole` (string, required, nullable): One of: `owner`, `member`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, optional, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "description": "string",
  "icon": null,
  "visibility": "open",
  "isDefault": false,
  "myRole": null,
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List teamspaces

Source: https://developers.lydie.co/api/teamspaces/list-teamspaces

`GET /v1/workspaces/{workspaceId}/teamspaces`

Open and closed teamspaces, plus private ones you belong to. Workspace owners and admins see all.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/teamspaces" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `deleted` (boolean, optional): List deleted teamspaces you could restore instead (admins, teamspace owners). Default: `false`.

## Response

- `teamspaces` (Teamspace[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `name` (string, required)
  - `description` (string, required)
  - `icon` (string, required, nullable)
  - `visibility` (string, required): One of: `open`, `closed`, `private`.
  - `isDefault` (boolean, required)
  - `myRole` (string, required, nullable): One of: `owner`, `member`.
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
  - `deletedAt` (timestamp, optional, nullable)

```json
{
  "teamspaces": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "name": "Notes",
      "description": "string",
      "icon": null,
      "visibility": "open",
      "isDefault": false,
      "myRole": null,
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z",
      "deletedAt": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a teamspace

Source: https://developers.lydie.co/api/teamspaces/create-a-teamspace

`POST /v1/workspaces/{workspaceId}/teamspaces`

You become its owner. Guests cannot create teamspaces.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/teamspaces" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Notes"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `id` (string, optional): Client-minted id. Generated when omitted. (1–64 chars)
- `name` (string, required): (1–100 chars)
- `description` (string, optional): Default: `""`. (≤ 2000 chars)
- `icon` (string, optional, nullable): Default: `null`. (≤ 100 chars)
- `visibility` (string, optional): One of: `open`, `closed`, `private`. Default: `"open"`.
- `isDefault` (boolean, optional): Default: `false`.

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `name` (string, required)
- `description` (string, required)
- `icon` (string, required, nullable)
- `visibility` (string, required): One of: `open`, `closed`, `private`.
- `isDefault` (boolean, required)
- `myRole` (string, required, nullable): One of: `owner`, `member`.
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)
- `deletedAt` (timestamp, optional, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "description": "string",
  "icon": null,
  "visibility": "open",
  "isDefault": false,
  "myRole": null,
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z",
  "deletedAt": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Invitations

Source: https://developers.lydie.co/api/invitations

Email invitations to join a workspace.

## Endpoints

- [Accept an invitation](https://developers.lydie.co/api/invitations/accept-an-invitation.md): `POST /v1/invitations/accept`
- [Decline an invitation](https://developers.lydie.co/api/invitations/decline-an-invitation.md): `POST /v1/invitations/decline`
- [Look up an invitation by its token](https://developers.lydie.co/api/invitations/look-up-an-invitation-by-its-token.md): `GET /v1/invitations/lookup`
- [Revoke an invitation](https://developers.lydie.co/api/invitations/revoke-an-invitation.md): `DELETE /v1/invitations/{invitationId}`
- [Resend an invitation](https://developers.lydie.co/api/invitations/resend-an-invitation.md): `POST /v1/invitations/{invitationId}/resend`
- [List pending invitations](https://developers.lydie.co/api/invitations/list-pending-invitations.md): `GET /v1/workspaces/{workspaceId}/invitations`
- [Invite someone by email](https://developers.lydie.co/api/invitations/invite-someone-by-email.md): `POST /v1/workspaces/{workspaceId}/invitations`

## The Invitation object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `email` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `status` (string, required): One of: `pending`, `accepted`, `declined`, `revoked`.
- `expiresAt` (timestamp, required)
- `documentId` (string, required, nullable)
- `documentLevel` (string, required, nullable): One of: `view`, `comment`, `edit`, `full`.
- `teamspaceIds` (string[], required)
- `invitedBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "email": "ada@example.com",
  "role": "owner",
  "status": "pending",
  "expiresAt": "2026-11-12T09:30:00.000Z",
  "documentId": null,
  "documentLevel": null,
  "teamspaceIds": [
    "string"
  ],
  "invitedBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

---

# Accept an invitation

Source: https://developers.lydie.co/api/invitations/accept-an-invitation

`POST /v1/invitations/accept`

The signed-in account's email must match the invitation.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/invitations/accept" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "string"
  }'
```

## Body

- `token` (string, required): (20–200 chars)

## Response

- `workspaceId` (string, required): (1–64 chars)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `documentId` (string, required, nullable)

```json
{
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "role": "owner",
  "documentId": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Decline an invitation

Source: https://developers.lydie.co/api/invitations/decline-an-invitation

`POST /v1/invitations/decline`

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/invitations/decline" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "token": "string"
  }'
```

## Body

- `token` (string, required): (20–200 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Look up an invitation by its token

Source: https://developers.lydie.co/api/invitations/look-up-an-invitation-by-its-token

`GET /v1/invitations/lookup`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/invitations/lookup?token=string" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Query parameters

- `token` (string, required): (20–200 chars)

## Response

- `invitation` (Invitation, required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `email` (string, required)
  - `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
  - `status` (string, required): One of: `pending`, `accepted`, `declined`, `revoked`.
  - `expiresAt` (timestamp, required)
  - `documentId` (string, required, nullable)
  - `documentLevel` (string, required, nullable): One of: `view`, `comment`, `edit`, `full`.
  - `teamspaceIds` (string[], required)
  - `invitedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
- `workspaceName` (string, required)
- `invitedByName` (string, required, nullable)
- `documentTitle` (string, required, nullable)

```json
{
  "invitation": {
    "id": "string",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "email": "ada@example.com",
    "role": "owner",
    "status": "pending",
    "expiresAt": "2026-11-12T09:30:00.000Z",
    "documentId": null,
    "documentLevel": null,
    "teamspaceIds": [
      "string"
    ],
    "invitedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z"
  },
  "workspaceName": "string",
  "invitedByName": null,
  "documentTitle": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Revoke an invitation

Source: https://developers.lydie.co/api/invitations/revoke-an-invitation

`DELETE /v1/invitations/{invitationId}`

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/invitations/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `invitationId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Resend an invitation

Source: https://developers.lydie.co/api/invitations/resend-an-invitation

`POST /v1/invitations/{invitationId}/resend`

Sends a new link and extends the expiry. The previous link stops working.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/invitations/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/resend" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `invitationId` (string, required): (1–64 chars)

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `email` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `status` (string, required): One of: `pending`, `accepted`, `declined`, `revoked`.
- `expiresAt` (timestamp, required)
- `documentId` (string, required, nullable)
- `documentLevel` (string, required, nullable): One of: `view`, `comment`, `edit`, `full`.
- `teamspaceIds` (string[], required)
- `invitedBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "email": "ada@example.com",
  "role": "owner",
  "status": "pending",
  "expiresAt": "2026-11-12T09:30:00.000Z",
  "documentId": null,
  "documentLevel": null,
  "teamspaceIds": [
    "string"
  ],
  "invitedBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List pending invitations

Source: https://developers.lydie.co/api/invitations/list-pending-invitations

`GET /v1/workspaces/{workspaceId}/invitations`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/invitations" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `invitations` (Invitation[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `email` (string, required)
  - `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
  - `status` (string, required): One of: `pending`, `accepted`, `declined`, `revoked`.
  - `expiresAt` (timestamp, required)
  - `documentId` (string, required, nullable)
  - `documentLevel` (string, required, nullable): One of: `view`, `comment`, `edit`, `full`.
  - `teamspaceIds` (string[], required)
  - `invitedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)

```json
{
  "invitations": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "email": "ada@example.com",
      "role": "owner",
      "status": "pending",
      "expiresAt": "2026-11-12T09:30:00.000Z",
      "documentId": null,
      "documentLevel": null,
      "teamspaceIds": [
        "string"
      ],
      "invitedBy": null,
      "createdAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Invite someone by email

Source: https://developers.lydie.co/api/invitations/invite-someone-by-email

`POST /v1/workspaces/{workspaceId}/invitations`

Emails an invitation link (valid for 7 days). Inviting an email that already has a pending invitation sends a fresh link. Owners and admins only.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/invitations" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@example.com"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `email` (string, required): (≤ 320 chars)
- `role` (string, optional): One of: `admin`, `member`, `guest`. Default: `"member"`.
- `teamspaceIds` (string[], optional): Teamspaces the invitee joins on accepting (not for guests). Default: `[]`. (≤ 50 items)

## Response

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `email` (string, required)
- `role` (string, required): One of: `owner`, `admin`, `member`, `guest`.
- `status` (string, required): One of: `pending`, `accepted`, `declined`, `revoked`.
- `expiresAt` (timestamp, required)
- `documentId` (string, required, nullable)
- `documentLevel` (string, required, nullable): One of: `view`, `comment`, `edit`, `full`.
- `teamspaceIds` (string[], required)
- `invitedBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "email": "ada@example.com",
  "role": "owner",
  "status": "pending",
  "expiresAt": "2026-11-12T09:30:00.000Z",
  "documentId": null,
  "documentLevel": null,
  "teamspaceIds": [
    "string"
  ],
  "invitedBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Sharing

Source: https://developers.lydie.co/api/sharing

Who can see a page: grants to people, teamspaces or the whole workspace, restricted pages, and public links.

## Endpoints

- [Share a page](https://developers.lydie.co/api/sharing/share-a-page.md): `POST /v1/documents/{documentId}/grants`
- [Stop sharing a page](https://developers.lydie.co/api/sharing/stop-sharing-a-page.md): `DELETE /v1/documents/{documentId}/grants/{grantId}`
- [Share a page with someone by email](https://developers.lydie.co/api/sharing/share-a-page-with-someone-by-email.md): `POST /v1/documents/{documentId}/invite`
- [Restrict or unrestrict a page](https://developers.lydie.co/api/sharing/restrict-or-unrestrict-a-page.md): `POST /v1/documents/{documentId}/restricted`
- [List a page's public links](https://developers.lydie.co/api/sharing/list-a-pages-public-links.md): `GET /v1/documents/{documentId}/share-links`
- [Create a public link](https://developers.lydie.co/api/sharing/create-a-public-link.md): `POST /v1/documents/{documentId}/share-links`
- [Get a page's sharing settings](https://developers.lydie.co/api/sharing/get-a-pages-sharing-settings.md): `GET /v1/documents/{documentId}/sharing`
- [Change a public link](https://developers.lydie.co/api/sharing/change-a-public-link.md): `PATCH /v1/share-links/{shareLinkId}`
- [Revoke a public link](https://developers.lydie.co/api/sharing/revoke-a-public-link.md): `DELETE /v1/share-links/{shareLinkId}`

## The DocumentGrant object

- `id` (string, required): (1–64 chars)
- `documentId` (string, required)
- `principalType` (string, required): One of: `user`, `teamspace`, `workspace`.
- `principalId` (string, required)
- `level` (string, required): One of: `view`, `comment`, `edit`, `full`.
- `createdBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "principalType": "user",
  "principalId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "level": "view",
  "createdBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

---

# Share a page

Source: https://developers.lydie.co/api/sharing/share-a-page

`POST /v1/documents/{documentId}/grants`

Gives a user, a teamspace's members or everyone in the workspace (principalType workspace, principalId = workspace id) a level on the page and its subpages. Needs full access.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/grants" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "principalType": "user",
    "principalId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "level": "view"
  }'
```

## Path parameters

- `documentId` (ULID, required)

## Body

- `principalType` (string, required): One of: `user`, `teamspace`, `workspace`.
- `principalId` (string, required): (1–64 chars)
- `level` (string, required): One of: `view`, `comment`, `edit`, `full`.

## Response

- `id` (string, required): (1–64 chars)
- `documentId` (string, required)
- `principalType` (string, required): One of: `user`, `teamspace`, `workspace`.
- `principalId` (string, required)
- `level` (string, required): One of: `view`, `comment`, `edit`, `full`.
- `createdBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "principalType": "user",
  "principalId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "level": "view",
  "createdBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Stop sharing a page

Source: https://developers.lydie.co/api/sharing/stop-sharing-a-page

`DELETE /v1/documents/{documentId}/grants/{grantId}`

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/grants/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `documentId` (ULID, required)
- `grantId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Share a page with someone by email

Source: https://developers.lydie.co/api/sharing/share-a-page-with-someone-by-email

`POST /v1/documents/{documentId}/invite`

Members get a grant. Someone with an account who is not a member is added as a guest. Anyone else is emailed an invitation that makes them a guest with this access.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/invite" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "ada@example.com",
    "level": "view"
  }'
```

## Path parameters

- `documentId` (ULID, required)

## Body

- `email` (string, required): (≤ 320 chars)
- `level` (string, required): One of: `view`, `comment`, `edit`, `full`.

## Response

- `status` (string, required): One of: `granted`, `added_as_guest`, `invited`.
- `userId` (string, required, nullable): (1–64 chars)
- `invitationId` (string, required, nullable)

```json
{
  "status": "granted",
  "userId": null,
  "invitationId": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Restrict or unrestrict a page

Source: https://developers.lydie.co/api/sharing/restrict-or-unrestrict-a-page

`POST /v1/documents/{documentId}/restricted`

A restricted page does not inherit access from its parent or its teamspace: only its own grants apply (to it and its subpages). Restricting gives you full access so you keep it.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/restricted" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "restricted": false
  }'
```

## Path parameters

- `documentId` (ULID, required)

## Body

- `restricted` (boolean, required)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List a page's public links

Source: https://developers.lydie.co/api/sharing/list-a-pages-public-links

`GET /v1/documents/{documentId}/share-links`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/share-links" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `documentId` (ULID, required)

## Response

- `shareLinks` (ShareLink[], required)
  - `id` (string, required): (1–64 chars)
  - `documentId` (string, required)
  - `tokenHint` (string, required)
  - `includeSubpages` (boolean, required)
  - `expiresAt` (timestamp, required, nullable)
  - `hasPassword` (boolean, required)
  - `createdBy` (string, required, nullable)
  - `createdAt` (timestamp, required)

```json
{
  "shareLinks": [
    {
      "id": "string",
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "tokenHint": "string",
      "includeSubpages": false,
      "expiresAt": null,
      "hasPassword": false,
      "createdBy": null,
      "createdAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create a public link

Source: https://developers.lydie.co/api/sharing/create-a-public-link

`POST /v1/documents/{documentId}/share-links`

Creates a view-only public link to the page (and, by default, its unrestricted subpages). The token is returned only once. Needs full access.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/share-links" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `documentId` (ULID, required)

## Body

- `includeSubpages` (boolean, optional): Default: `true`.
- `expiresAt` (timestamp, optional, nullable): Default: `null`.
- `password` (string, optional, nullable): Default: `null`. (4–200 chars)

## Response

- `shareLink` (ShareLink, required)
  - `id` (string, required): (1–64 chars)
  - `documentId` (string, required)
  - `tokenHint` (string, required)
  - `includeSubpages` (boolean, required)
  - `expiresAt` (timestamp, required, nullable)
  - `hasPassword` (boolean, required)
  - `createdBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
- `token` (string, required)
- `url` (string, required)

```json
{
  "shareLink": {
    "id": "string",
    "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "tokenHint": "string",
    "includeSubpages": false,
    "expiresAt": null,
    "hasPassword": false,
    "createdBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z"
  },
  "token": "string",
  "url": "string"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a page's sharing settings

Source: https://developers.lydie.co/api/sharing/get-a-pages-sharing-settings

`GET /v1/documents/{documentId}/sharing`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/sharing" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `documentId` (ULID, required)

## Response

- `documentId` (ULID, required)
- `myLevel` (string, required): One of: `view`, `comment`, `edit`, `full`.
- `restricted` (boolean, required)
- `teamspaceId` (string, required, nullable)
- `privateOwnerId` (string, required, nullable)
- `grants` (DocumentGrant[], required): Grants on this page.
  - `id` (string, required): (1–64 chars)
  - `documentId` (string, required)
  - `principalType` (string, required): One of: `user`, `teamspace`, `workspace`.
  - `principalId` (string, required)
  - `level` (string, required): One of: `view`, `comment`, `edit`, `full`.
  - `createdBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
- `inherited` (object[], required): Grants on ancestors that apply here, nearest first, up to a restricted page.
  - `documentId` (string, required)
  - `title` (string, required)
  - `grants` (DocumentGrant[], required)
    - `id` (string, required): (1–64 chars)
    - `documentId` (string, required)
    - `principalType` (string, required): One of: `user`, `teamspace`, `workspace`.
    - `principalId` (string, required)
    - `level` (string, required): One of: `view`, `comment`, `edit`, `full`.
    - `createdBy` (string, required, nullable)
    - `createdAt` (timestamp, required)
- `people` (object[], required): Everyone who can access the page and their resolved level.
  - `userId` (string, required): (1–64 chars)
  - `name` (string, required)
  - `email` (string, required)
  - `level` (string, required): One of: `view`, `comment`, `edit`, `full`.

```json
{
  "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "myLevel": "view",
  "restricted": false,
  "teamspaceId": null,
  "privateOwnerId": null,
  "grants": [
    {
      "id": "string",
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "principalType": "user",
      "principalId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "level": "view",
      "createdBy": null,
      "createdAt": "2026-11-12T09:30:00.000Z"
    }
  ],
  "inherited": [
    {
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "title": "Meeting notes",
      "grants": [
        {
          "id": null,
          "documentId": null,
          "principalType": "user",
          "principalId": null,
          "level": "view",
          "createdBy": null,
          "createdAt": "2026-11-12T09:30:00.000Z"
        }
      ]
    }
  ],
  "people": [
    {
      "userId": "kG7qL2m9XzP4tR8w",
      "name": "Notes",
      "email": "ada@example.com",
      "level": "view"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a public link

Source: https://developers.lydie.co/api/sharing/change-a-public-link

`PATCH /v1/share-links/{shareLinkId}`

Set expiresAt or password to null to remove them.

Scope: `docs:write`.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/share-links/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `shareLinkId` (string, required): (1–64 chars)

## Body

- `includeSubpages` (boolean, optional)
- `expiresAt` (timestamp, optional, nullable)
- `password` (string, optional, nullable): (4–200 chars)

## Response

- `id` (string, required): (1–64 chars)
- `documentId` (string, required)
- `tokenHint` (string, required)
- `includeSubpages` (boolean, required)
- `expiresAt` (timestamp, required, nullable)
- `hasPassword` (boolean, required)
- `createdBy` (string, required, nullable)
- `createdAt` (timestamp, required)

```json
{
  "id": "string",
  "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "tokenHint": "string",
  "includeSubpages": false,
  "expiresAt": null,
  "hasPassword": false,
  "createdBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Revoke a public link

Source: https://developers.lydie.co/api/sharing/revoke-a-public-link

`DELETE /v1/share-links/{shareLinkId}`

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/share-links/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `shareLinkId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Notifications

Source: https://developers.lydie.co/api/notifications

Your inbox: mentions, shares and accepted invitations.

## Endpoints

- [List notifications](https://developers.lydie.co/api/notifications/list-notifications.md): `GET /v1/notifications`
- [Archive notifications](https://developers.lydie.co/api/notifications/archive-notifications.md): `POST /v1/notifications/archive`
- [Get notification preferences](https://developers.lydie.co/api/notifications/get-notification-preferences.md): `GET /v1/notifications/preferences`
- [Set notification preferences](https://developers.lydie.co/api/notifications/set-notification-preferences.md): `PUT /v1/notifications/preferences`
- [Mark notifications read](https://developers.lydie.co/api/notifications/mark-notifications-read.md): `POST /v1/notifications/read`
- [Mark all notifications read](https://developers.lydie.co/api/notifications/mark-all-notifications-read.md): `POST /v1/notifications/read-all`

## The Notification object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `kind` (string, required): One of: `mention`, `share`, `invitation_accepted`, `assigned`.
- `documentId` (string, required, nullable)
- `actorId` (string, required, nullable): Who caused it; null when unknown.
- `data` (object, required): mention: { title, actorName, snippet }; share: { title, actorName, level }; invitation_accepted: { email, name, workspaceName, documentId? }; assigned: { title, actorName, propertyName, propertyId, databaseId }
- `readAt` (string, required, nullable)
- `archivedAt` (string, required, nullable)
- `createdAt` (string, required)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "kind": "mention",
  "documentId": null,
  "actorId": null,
  "data": {},
  "readAt": null,
  "archivedAt": null,
  "createdAt": "string"
}
```

---

# List notifications

Source: https://developers.lydie.co/api/notifications/list-notifications

`GET /v1/notifications`

Your notifications, newest first. Archived ones only with archived: true.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/notifications" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Query parameters

- `workspaceId` (string, optional): (1–64 chars)
- `unread` (boolean, optional): Only unread ones. Default: `false`.
- `archived` (boolean, optional): Archived ones instead of the inbox. Default: `false`.
- `before` (string, optional): Page: notifications older than this id. (1–64 chars)
- `limit` (integer, optional): Default: `50`. (1–200)

## Response

- `notifications` (Notification[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `kind` (string, required): One of: `mention`, `share`, `invitation_accepted`, `assigned`.
  - `documentId` (string, required, nullable)
  - `actorId` (string, required, nullable): Who caused it; null when unknown.
  - `data` (object, required): mention: { title, actorName, snippet }; share: { title, actorName, level }; invitation_accepted: { email, name, workspaceName, documentId? }; assigned: { title, actorName, propertyName, propertyId, databaseId }
  - `readAt` (string, required, nullable)
  - `archivedAt` (string, required, nullable)
  - `createdAt` (string, required)
- `unread` (integer, required)

```json
{
  "notifications": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "kind": "mention",
      "documentId": null,
      "actorId": null,
      "data": {},
      "readAt": null,
      "archivedAt": null,
      "createdAt": "string"
    }
  ],
  "unread": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Archive notifications

Source: https://developers.lydie.co/api/notifications/archive-notifications

`POST /v1/notifications/archive`

Moves them out of the inbox (and off your devices); archived: false brings them back.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/notifications/archive" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "string"
    ]
  }'
```

## Body

- `ids` (string[], required): (1–500 items)
- `archived` (boolean, optional): Default: `true`.

## Response

- `updated` (integer, required)

```json
{
  "updated": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get notification preferences

Source: https://developers.lydie.co/api/notifications/get-notification-preferences

`GET /v1/notifications/preferences`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/notifications/preferences" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Response

- `email` (string, required): One of: `off`, `mentions`, `all`.

```json
{
  "email": "off"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Set notification preferences

Source: https://developers.lydie.co/api/notifications/set-notification-preferences

`PUT /v1/notifications/preferences`

email: off (default), mentions (mail for mentions), all (every notification).

Scope: `docs:write`.

## Request

```bash
curl -X PUT "https://api.lydie.co/v1/notifications/preferences" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "off"
  }'
```

## Body

- `email` (string, required): One of: `off`, `mentions`, `all`.

## Response

- `email` (string, required): One of: `off`, `mentions`, `all`.

```json
{
  "email": "off"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Mark notifications read

Source: https://developers.lydie.co/api/notifications/mark-notifications-read

`POST /v1/notifications/read`

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/notifications/read" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "string"
    ]
  }'
```

## Body

- `ids` (string[], required): (1–500 items)
- `read` (boolean, optional): false: mark unread. Default: `true`.

## Response

- `updated` (integer, required)

```json
{
  "updated": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Mark all notifications read

Source: https://developers.lydie.co/api/notifications/mark-all-notifications-read

`POST /v1/notifications/read-all`

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/notifications/read-all" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Body

- `workspaceId` (string, optional): (1–64 chars)

## Response

- `updated` (integer, required)

```json
{
  "updated": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Publishing

Source: https://developers.lydie.co/api/publishing

Publish documents to GitHub, WordPress or a webhook. A connection holds the credentials; a publication says what goes where.

## Endpoints

- [Get a connection](https://developers.lydie.co/api/publishing/get-a-connection.md): `GET /v1/connections/{id}`
- [Change a connection](https://developers.lydie.co/api/publishing/change-a-connection.md): `PATCH /v1/connections/{id}`
- [Remove a connection](https://developers.lydie.co/api/publishing/remove-a-connection.md): `DELETE /v1/connections/{id}`
- [Test a connection](https://developers.lydie.co/api/publishing/test-a-connection.md): `POST /v1/connections/{id}/test`
- [List publishing connectors](https://developers.lydie.co/api/publishing/list-publishing-connectors.md): `GET /v1/connectors`
- [Publish a document to a connection](https://developers.lydie.co/api/publishing/publish-a-document-to-a-connection.md): `POST /v1/documents/{documentId}/publications`
- [Get a publication](https://developers.lydie.co/api/publishing/get-a-publication.md): `GET /v1/publications/{id}`
- [Change a publication](https://developers.lydie.co/api/publishing/change-a-publication.md): `PATCH /v1/publications/{id}`
- [Remove a publication](https://developers.lydie.co/api/publishing/remove-a-publication.md): `DELETE /v1/publications/{id}`
- [Resolve a diverged document](https://developers.lydie.co/api/publishing/resolve-a-diverged-document.md): `POST /v1/publications/{id}/resolve`
- [Publish now](https://developers.lydie.co/api/publishing/publish-now.md): `POST /v1/publications/{id}/run`
- [List a publication's runs](https://developers.lydie.co/api/publishing/list-a-publications-runs.md): `GET /v1/publications/{id}/runs`
- [Unpublish](https://developers.lydie.co/api/publishing/unpublish.md): `POST /v1/publications/{id}/unpublish`
- [List connections](https://developers.lydie.co/api/publishing/list-connections.md): `GET /v1/workspaces/{workspaceId}/connections`
- [Connect a destination](https://developers.lydie.co/api/publishing/connect-a-destination.md): `POST /v1/workspaces/{workspaceId}/connections`
- [Start connecting with OAuth](https://developers.lydie.co/api/publishing/start-connecting-with-oauth.md): `POST /v1/workspaces/{workspaceId}/connections/authorize`
- [List publications](https://developers.lydie.co/api/publishing/list-publications.md): `GET /v1/workspaces/{workspaceId}/publications`

## The Publication object

- `id` (ULID, required)
- `workspaceId` (string, required): (1–64 chars)
- `connectionId` (ULID, required)
- `connector` (string, required)
- `documentId` (ULID, required)
- `includeSubpages` (boolean, required)
- `filter` (object, required, nullable): Publish only documents whose property equals this (lists: contains it).
  - `property` (string, required): (1–128 chars)
  - `equals` (any, required)
- `config` (object, required)
- `autoPublish` (boolean, required)
- `lastRunAt` (timestamp, required, nullable)
- `items` (PublicationItem[], required)
  - `id` (ULID, required)
  - `documentId` (ULID, required)
  - `state` (string, required): One of: `draft`, `scheduled`, `publishing`, `published`, `updated_pending`, `failed`, `unpublished`, `diverged`.
  - `externalId` (string, required, nullable)
  - `externalUrl` (string, required, nullable)
  - `lastPublishedAt` (timestamp, required, nullable)
  - `lastError` (object, required, nullable)
  - `divergence` (object, required, nullable): For diverged items: reason, base/ours/theirs (destination format), conflicts, marked text and the pull request.
  - `updatedAt` (timestamp, required)
- `createdBy` (string, required, nullable)
- `updatedBy` (string, required, nullable)
- `createdAt` (timestamp, required)
- `updatedAt` (timestamp, required)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "connector": "string",
  "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "includeSubpages": false,
  "filter": null,
  "config": {},
  "autoPublish": false,
  "lastRunAt": null,
  "items": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "state": "draft",
      "externalId": null,
      "externalUrl": null,
      "lastPublishedAt": null,
      "lastError": null,
      "divergence": null,
      "updatedAt": "2026-11-12T09:30:00.000Z"
    }
  ],
  "createdBy": null,
  "updatedBy": null,
  "createdAt": "2026-11-12T09:30:00.000Z",
  "updatedAt": "2026-11-12T09:30:00.000Z"
}
```

---

# Get a connection

Source: https://developers.lydie.co/api/publishing/get-a-connection

`GET /v1/connections/{id}`

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/connections/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `connection` (Connection, required): A destination account. Credentials are never returned.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connector` (string, required)
  - `name` (string, required)
  - `authMethod` (string, required): One of: `token`, `oauth2`, `generated`.
  - `settings` (object, required)
  - `credentialsHint` (string, required, nullable)
  - `account` (string, required, nullable): Who the credentials act as at the destination.
  - `status` (string, required): One of: `active`, `error`.
  - `lastError` (string, required, nullable)
  - `lastValidatedAt` (timestamp, required, nullable)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "connection": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connector": "string",
    "name": "Notes",
    "authMethod": "token",
    "settings": {},
    "credentialsHint": null,
    "account": null,
    "status": "active",
    "lastError": null,
    "lastValidatedAt": null,
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a connection

Source: https://developers.lydie.co/api/publishing/change-a-connection

`PATCH /v1/connections/{id}`

Renames a connection, changes its settings or replaces its credentials (checked with the destination first). Owners and admins only.

Scope: `docs:write`.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/connections/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `name` (string, optional): (1–120 chars)
- `settings` (object, optional)
- `credentials` (object, optional)

## Response

- `connection` (Connection, required): A destination account. Credentials are never returned.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connector` (string, required)
  - `name` (string, required)
  - `authMethod` (string, required): One of: `token`, `oauth2`, `generated`.
  - `settings` (object, required)
  - `credentialsHint` (string, required, nullable)
  - `account` (string, required, nullable): Who the credentials act as at the destination.
  - `status` (string, required): One of: `active`, `error`.
  - `lastError` (string, required, nullable)
  - `lastValidatedAt` (timestamp, required, nullable)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
- `warnings` (string[], required)

```json
{
  "connection": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connector": "string",
    "name": "Notes",
    "authMethod": "token",
    "settings": {},
    "credentialsHint": null,
    "account": null,
    "status": "active",
    "lastError": null,
    "lastValidatedAt": null,
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  },
  "warnings": [
    "string"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Remove a connection

Source: https://developers.lydie.co/api/publishing/remove-a-connection

`DELETE /v1/connections/{id}`

Removes a connection and its stored credentials. Refused while publications use it, unless `force` (they are removed too; what they published stays at the destination). Owners and admins only.

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/connections/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Query parameters

- `force` (boolean, optional): Default: `false`.

## Response

- `id` (ULID, required)
- `removedPublications` (integer, required)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
  "removedPublications": -9007199254740991
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Test a connection

Source: https://developers.lydie.co/api/publishing/test-a-connection

`POST /v1/connections/{id}/test`

Checks the stored credentials with the destination and records the result.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/connections/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/test" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `connection` (Connection, required): A destination account. Credentials are never returned.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connector` (string, required)
  - `name` (string, required)
  - `authMethod` (string, required): One of: `token`, `oauth2`, `generated`.
  - `settings` (object, required)
  - `credentialsHint` (string, required, nullable)
  - `account` (string, required, nullable): Who the credentials act as at the destination.
  - `status` (string, required): One of: `active`, `error`.
  - `lastError` (string, required, nullable)
  - `lastValidatedAt` (timestamp, required, nullable)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
- `ok` (boolean, required)
- `warnings` (string[], required)

```json
{
  "connection": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connector": "string",
    "name": "Notes",
    "authMethod": "token",
    "settings": {},
    "credentialsHint": null,
    "account": null,
    "status": "active",
    "lastError": null,
    "lastValidatedAt": null,
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  },
  "ok": false,
  "warnings": [
    "string"
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List publishing connectors

Source: https://developers.lydie.co/api/publishing/list-publishing-connectors

`GET /v1/connectors`

Destinations documents can be published to, with their auth methods, the settings a connection needs and the config a publication takes (JSON Schema), and what they can do.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/connectors" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Response

- `connectors` (ConnectorInfo[], required)
  - `id` (string, required)
  - `name` (string, required)
  - `description` (string, required)
  - `auth` (object[], required)
    - `type` (string, required): One of: `token`, `oauth2`, `generated`.
    - `label` (string, required)
    - `fields` (object, required, nullable): JSON Schema of the credentials to type in.
    - `available` (boolean, required): false: OAuth is not configured on this server.
  - `settingsSchema` (object, required)
  - `configSchema` (object, required)
  - `capabilities` (object, required)
    - `format` (string, required): One of: `markdown`, `html`, `json`.
    - `remoteState` (boolean, required)
    - `pull` (boolean, required)
    - `conflicts` (string, required): One of: `pullRequest`, `diverge`, `none`.
    - `assets` (string, required): One of: `files`, `upload`, `link`.
    - `unpublish` (string, required): One of: `delete`, `draft`, `notify`.
    - `drafts` (boolean, required)
    - `schedule` (boolean, required)

```json
{
  "connectors": [
    {
      "id": "string",
      "name": "Notes",
      "description": "string",
      "auth": [
        {
          "type": "token",
          "label": null,
          "fields": null,
          "available": null
        }
      ],
      "settingsSchema": {},
      "configSchema": {},
      "capabilities": {
        "format": "markdown",
        "remoteState": false,
        "pull": false,
        "conflicts": "pullRequest",
        "assets": "files",
        "unpublish": "delete",
        "drafts": false,
        "schedule": false
      }
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Publish a document to a connection

Source: https://developers.lydie.co/api/publishing/publish-a-document-to-a-connection

`POST /v1/documents/{documentId}/publications`

Creates a publication of a document (and its subpages with `includeSubpages`) to a connection, and queues the first run unless `publishNow` is false. `config` follows the connector's configSchema (connector.list). Needs edit access to the document.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/documents/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/publications" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
  }'
```

## Path parameters

- `documentId` (ULID, required)

## Body

- `connectionId` (ULID, required)
- `includeSubpages` (boolean, optional): Default: `false`.
- `filter` (object, optional, nullable): Publish only documents whose property equals this (lists: contains it). Default: `null`.
  - `property` (string, required): (1–128 chars)
  - `equals` (any, required)
- `config` (object, optional): Default: `{}`.
- `autoPublish` (boolean, optional): Default: `false`.
- `publishNow` (boolean, optional): Default: `true`.

## Response

- `publication` (Publication, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connectionId` (ULID, required)
  - `connector` (string, required)
  - `documentId` (ULID, required)
  - `includeSubpages` (boolean, required)
  - `filter` (object, required, nullable): Publish only documents whose property equals this (lists: contains it).
    - `property` (string, required): (1–128 chars)
    - `equals` (any, required)
  - `config` (object, required)
  - `autoPublish` (boolean, required)
  - `lastRunAt` (timestamp, required, nullable)
  - `items` (PublicationItem[], required)
    - `id` (ULID, required)
    - `documentId` (ULID, required)
    - `state` (string, required): One of: `draft`, `scheduled`, `publishing`, `published`, `updated_pending`, `failed`, `unpublished`, `diverged`.
    - `externalId` (string, required, nullable)
    - `externalUrl` (string, required, nullable)
    - `lastPublishedAt` (timestamp, required, nullable)
    - `lastError` (object, required, nullable)
    - `divergence` (object, required, nullable): For diverged items: reason, base/ours/theirs (destination format), conflicts, marked text and the pull request.
    - `updatedAt` (timestamp, required)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
- `run` (PublicationRun, required, nullable): A run and its log.
  - `id` (ULID, required)
  - `publicationId` (ULID, required)
  - `action` (string, required): One of: `publish`, `unpublish`, `resolve`.
  - `trigger` (string, required): One of: `manual`, `auto`, `poll`.
  - `options` (object, required)
  - `status` (string, required): One of: `queued`, `running`, `succeeded`, `partial`, `failed`, `cancelled`.
  - `attempt` (integer, required)
  - `runAt` (timestamp, required)
  - `steps` (object[], required)
    - `at` (timestamp, required)
    - `step` (string, required)
    - `status` (string, required): One of: `ok`, `skipped`, `error`, `info`.
    - `documentId` (string, optional)
    - `ms` (number, optional)
    - `detail` (object, optional)
  - `summary` (object, required, nullable)
  - `error` (object, required, nullable)
  - `requestedBy` (string, required)
  - `createdAt` (timestamp, required)
  - `startedAt` (timestamp, required, nullable)
  - `finishedAt` (timestamp, required, nullable)

```json
{
  "publication": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "connector": "string",
    "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "includeSubpages": false,
    "filter": null,
    "config": {},
    "autoPublish": false,
    "lastRunAt": null,
    "items": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "state": "draft",
        "externalId": null,
        "externalUrl": null,
        "lastPublishedAt": null,
        "lastError": null,
        "divergence": null,
        "updatedAt": "2026-11-12T09:30:00.000Z"
      }
    ],
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  },
  "run": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Get a publication

Source: https://developers.lydie.co/api/publishing/get-a-publication

`GET /v1/publications/{id}`

A publication with the state of each published document.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `publication` (Publication, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connectionId` (ULID, required)
  - `connector` (string, required)
  - `documentId` (ULID, required)
  - `includeSubpages` (boolean, required)
  - `filter` (object, required, nullable): Publish only documents whose property equals this (lists: contains it).
    - `property` (string, required): (1–128 chars)
    - `equals` (any, required)
  - `config` (object, required)
  - `autoPublish` (boolean, required)
  - `lastRunAt` (timestamp, required, nullable)
  - `items` (PublicationItem[], required)
    - `id` (ULID, required)
    - `documentId` (ULID, required)
    - `state` (string, required): One of: `draft`, `scheduled`, `publishing`, `published`, `updated_pending`, `failed`, `unpublished`, `diverged`.
    - `externalId` (string, required, nullable)
    - `externalUrl` (string, required, nullable)
    - `lastPublishedAt` (timestamp, required, nullable)
    - `lastError` (object, required, nullable)
    - `divergence` (object, required, nullable): For diverged items: reason, base/ours/theirs (destination format), conflicts, marked text and the pull request.
    - `updatedAt` (timestamp, required)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "publication": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "connector": "string",
    "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "includeSubpages": false,
    "filter": null,
    "config": {},
    "autoPublish": false,
    "lastRunAt": null,
    "items": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "state": "draft",
        "externalId": null,
        "externalUrl": null,
        "lastPublishedAt": null,
        "lastError": null,
        "divergence": null,
        "updatedAt": "2026-11-12T09:30:00.000Z"
      }
    ],
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Change a publication

Source: https://developers.lydie.co/api/publishing/change-a-publication

`PATCH /v1/publications/{id}`

Scope: `docs:write`.

## Request

```bash
curl -X PATCH "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `includeSubpages` (boolean, optional)
- `filter` (object, optional, nullable): Publish only documents whose property equals this (lists: contains it).
  - `property` (string, required): (1–128 chars)
  - `equals` (any, required)
- `config` (object, optional)
- `autoPublish` (boolean, optional)

## Response

- `publication` (Publication, required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connectionId` (ULID, required)
  - `connector` (string, required)
  - `documentId` (ULID, required)
  - `includeSubpages` (boolean, required)
  - `filter` (object, required, nullable): Publish only documents whose property equals this (lists: contains it).
    - `property` (string, required): (1–128 chars)
    - `equals` (any, required)
  - `config` (object, required)
  - `autoPublish` (boolean, required)
  - `lastRunAt` (timestamp, required, nullable)
  - `items` (PublicationItem[], required)
    - `id` (ULID, required)
    - `documentId` (ULID, required)
    - `state` (string, required): One of: `draft`, `scheduled`, `publishing`, `published`, `updated_pending`, `failed`, `unpublished`, `diverged`.
    - `externalId` (string, required, nullable)
    - `externalUrl` (string, required, nullable)
    - `lastPublishedAt` (timestamp, required, nullable)
    - `lastError` (object, required, nullable)
    - `divergence` (object, required, nullable): For diverged items: reason, base/ours/theirs (destination format), conflicts, marked text and the pull request.
    - `updatedAt` (timestamp, required)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "publication": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "connector": "string",
    "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "includeSubpages": false,
    "filter": null,
    "config": {},
    "autoPublish": false,
    "lastRunAt": null,
    "items": [
      {
        "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "state": "draft",
        "externalId": null,
        "externalUrl": null,
        "lastPublishedAt": null,
        "lastError": null,
        "divergence": null,
        "updatedAt": "2026-11-12T09:30:00.000Z"
      }
    ],
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Remove a publication

Source: https://developers.lydie.co/api/publishing/remove-a-publication

`DELETE /v1/publications/{id}`

Stops publishing. What was published stays at the destination: run publication.unpublish first to take it down.

Scope: `docs:write`.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `id` (ULID, required)

```json
{
  "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Resolve a diverged document

Source: https://developers.lydie.co/api/publishing/resolve-a-diverged-document

`POST /v1/publications/{id}/resolve`

Settles a document that changed both in Lydie and at the destination. `overwrite` publishes the Lydie version over the remote edits. `keepRemote` accepts the destination's version as published without changing the document. `pull` merges the remote edits into the document (connectors that can pull) and publishes the result; a merge conflict leaves it diverged.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/resolve" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "resolution": "overwrite"
  }'
```

## Path parameters

- `id` (ULID, required)

## Body

- `documentId` (ULID, required)
- `resolution` (string, required): One of: `overwrite`, `keepRemote`, `pull`.

## Response

- `run` (PublicationRun, required): A run and its log.
  - `id` (ULID, required)
  - `publicationId` (ULID, required)
  - `action` (string, required): One of: `publish`, `unpublish`, `resolve`.
  - `trigger` (string, required): One of: `manual`, `auto`, `poll`.
  - `options` (object, required)
  - `status` (string, required): One of: `queued`, `running`, `succeeded`, `partial`, `failed`, `cancelled`.
  - `attempt` (integer, required)
  - `runAt` (timestamp, required)
  - `steps` (object[], required)
    - `at` (timestamp, required)
    - `step` (string, required)
    - `status` (string, required): One of: `ok`, `skipped`, `error`, `info`.
    - `documentId` (string, optional)
    - `ms` (number, optional)
    - `detail` (object, optional)
  - `summary` (object, required, nullable)
  - `error` (object, required, nullable)
  - `requestedBy` (string, required)
  - `createdAt` (timestamp, required)
  - `startedAt` (timestamp, required, nullable)
  - `finishedAt` (timestamp, required, nullable)

```json
{
  "run": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "publicationId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "action": "publish",
    "trigger": "manual",
    "options": {},
    "status": "queued",
    "attempt": -9007199254740991,
    "runAt": "2026-11-12T09:30:00.000Z",
    "steps": [
      {
        "at": "2026-11-12T09:30:00.000Z",
        "step": "string",
        "status": "ok",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "ms": 0,
        "detail": {}
      }
    ],
    "summary": null,
    "error": null,
    "requestedBy": "string",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "startedAt": null,
    "finishedAt": null
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Publish now

Source: https://developers.lydie.co/api/publishing/publish-now

`POST /v1/publications/{id}/run`

Queues a run that publishes what changed: unchanged documents are skipped (content hash), remote edits are detected and pulled back or shown as a divergence, never overwritten. `force` republishes unchanged documents. `scheduledAt` runs it later. A waiting run absorbs repeated requests.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/run" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Path parameters

- `id` (ULID, required)

## Body

- `force` (boolean, optional): Default: `false`.
- `scheduledAt` (timestamp, optional)

## Response

- `run` (PublicationRun, required): A run and its log.
  - `id` (ULID, required)
  - `publicationId` (ULID, required)
  - `action` (string, required): One of: `publish`, `unpublish`, `resolve`.
  - `trigger` (string, required): One of: `manual`, `auto`, `poll`.
  - `options` (object, required)
  - `status` (string, required): One of: `queued`, `running`, `succeeded`, `partial`, `failed`, `cancelled`.
  - `attempt` (integer, required)
  - `runAt` (timestamp, required)
  - `steps` (object[], required)
    - `at` (timestamp, required)
    - `step` (string, required)
    - `status` (string, required): One of: `ok`, `skipped`, `error`, `info`.
    - `documentId` (string, optional)
    - `ms` (number, optional)
    - `detail` (object, optional)
  - `summary` (object, required, nullable)
  - `error` (object, required, nullable)
  - `requestedBy` (string, required)
  - `createdAt` (timestamp, required)
  - `startedAt` (timestamp, required, nullable)
  - `finishedAt` (timestamp, required, nullable)

```json
{
  "run": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "publicationId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "action": "publish",
    "trigger": "manual",
    "options": {},
    "status": "queued",
    "attempt": -9007199254740991,
    "runAt": "2026-11-12T09:30:00.000Z",
    "steps": [
      {
        "at": "2026-11-12T09:30:00.000Z",
        "step": "string",
        "status": "ok",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "ms": 0,
        "detail": {}
      }
    ],
    "summary": null,
    "error": null,
    "requestedBy": "string",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "startedAt": null,
    "finishedAt": null
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List a publication's runs

Source: https://developers.lydie.co/api/publishing/list-a-publications-runs

`GET /v1/publications/{id}/runs`

Runs newest first, with their step log (requests, commits, deliveries, errors).

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/runs" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Query parameters

- `runId` (ULID, optional)
- `limit` (integer, optional): Default: `20`. (1–100)

## Response

- `runs` (PublicationRun[], required)
  - `id` (ULID, required)
  - `publicationId` (ULID, required)
  - `action` (string, required): One of: `publish`, `unpublish`, `resolve`.
  - `trigger` (string, required): One of: `manual`, `auto`, `poll`.
  - `options` (object, required)
  - `status` (string, required): One of: `queued`, `running`, `succeeded`, `partial`, `failed`, `cancelled`.
  - `attempt` (integer, required)
  - `runAt` (timestamp, required)
  - `steps` (object[], required)
    - `at` (timestamp, required)
    - `step` (string, required)
    - `status` (string, required): One of: `ok`, `skipped`, `error`, `info`.
    - `documentId` (string, optional)
    - `ms` (number, optional)
    - `detail` (object, optional)
  - `summary` (object, required, nullable)
  - `error` (object, required, nullable)
  - `requestedBy` (string, required)
  - `createdAt` (timestamp, required)
  - `startedAt` (timestamp, required, nullable)
  - `finishedAt` (timestamp, required, nullable)

```json
{
  "runs": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "publicationId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "action": "publish",
      "trigger": "manual",
      "options": {},
      "status": "queued",
      "attempt": -9007199254740991,
      "runAt": "2026-11-12T09:30:00.000Z",
      "steps": [
        {
          "at": "2026-11-12T09:30:00.000Z",
          "step": null,
          "status": "ok",
          "documentId": null,
          "ms": null,
          "detail": null
        }
      ],
      "summary": null,
      "error": null,
      "requestedBy": "string",
      "createdAt": "2026-11-12T09:30:00.000Z",
      "startedAt": null,
      "finishedAt": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Unpublish

Source: https://developers.lydie.co/api/publishing/unpublish

`POST /v1/publications/{id}/unpublish`

Queues a run that takes every published document down at the destination (deletes the file, sets the post back to draft or trashes it, or notifies, per connector).

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/publications/01JCQ3V5MZ8G4ZK2X7T9R6N1PB/unpublish" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `id` (ULID, required)

## Response

- `run` (PublicationRun, required): A run and its log.
  - `id` (ULID, required)
  - `publicationId` (ULID, required)
  - `action` (string, required): One of: `publish`, `unpublish`, `resolve`.
  - `trigger` (string, required): One of: `manual`, `auto`, `poll`.
  - `options` (object, required)
  - `status` (string, required): One of: `queued`, `running`, `succeeded`, `partial`, `failed`, `cancelled`.
  - `attempt` (integer, required)
  - `runAt` (timestamp, required)
  - `steps` (object[], required)
    - `at` (timestamp, required)
    - `step` (string, required)
    - `status` (string, required): One of: `ok`, `skipped`, `error`, `info`.
    - `documentId` (string, optional)
    - `ms` (number, optional)
    - `detail` (object, optional)
  - `summary` (object, required, nullable)
  - `error` (object, required, nullable)
  - `requestedBy` (string, required)
  - `createdAt` (timestamp, required)
  - `startedAt` (timestamp, required, nullable)
  - `finishedAt` (timestamp, required, nullable)

```json
{
  "run": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "publicationId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "action": "publish",
    "trigger": "manual",
    "options": {},
    "status": "queued",
    "attempt": -9007199254740991,
    "runAt": "2026-11-12T09:30:00.000Z",
    "steps": [
      {
        "at": "2026-11-12T09:30:00.000Z",
        "step": "string",
        "status": "ok",
        "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
        "ms": 0,
        "detail": {}
      }
    ],
    "summary": null,
    "error": null,
    "requestedBy": "string",
    "createdAt": "2026-11-12T09:30:00.000Z",
    "startedAt": null,
    "finishedAt": null
  }
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List connections

Source: https://developers.lydie.co/api/publishing/list-connections

`GET /v1/workspaces/{workspaceId}/connections`

The workspace's destination connections (no credentials). Members and above.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/connections" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `connections` (Connection[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connector` (string, required)
  - `name` (string, required)
  - `authMethod` (string, required): One of: `token`, `oauth2`, `generated`.
  - `settings` (object, required)
  - `credentialsHint` (string, required, nullable)
  - `account` (string, required, nullable): Who the credentials act as at the destination.
  - `status` (string, required): One of: `active`, `error`.
  - `lastError` (string, required, nullable)
  - `lastValidatedAt` (timestamp, required, nullable)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "connections": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "connector": "string",
      "name": "Notes",
      "authMethod": "token",
      "settings": {},
      "credentialsHint": null,
      "account": null,
      "status": "active",
      "lastError": null,
      "lastValidatedAt": null,
      "createdBy": null,
      "updatedBy": null,
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Connect a destination

Source: https://developers.lydie.co/api/publishing/connect-a-destination

`POST /v1/workspaces/{workspaceId}/connections`

Connects a workspace to a destination with a token or generated secret (OAuth: connection.authorize). The credentials are checked with the destination first and stored encrypted; they are never returned, except generated secrets (`revealed`), once. Owners and admins only.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/connections" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "connector": "string",
    "name": "Notes"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `connector` (string, required): (≥ 1 chars)
- `name` (string, required): (1–120 chars)
- `authMethod` (string, optional): One of: `token`, `generated`.
- `settings` (object, optional): Default: `{}`.
- `credentials` (object, optional): Default: `{}`.

## Response

- `connection` (Connection, required): A destination account. Credentials are never returned.
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connector` (string, required)
  - `name` (string, required)
  - `authMethod` (string, required): One of: `token`, `oauth2`, `generated`.
  - `settings` (object, required)
  - `credentialsHint` (string, required, nullable)
  - `account` (string, required, nullable): Who the credentials act as at the destination.
  - `status` (string, required): One of: `active`, `error`.
  - `lastError` (string, required, nullable)
  - `lastValidatedAt` (timestamp, required, nullable)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)
- `warnings` (string[], required)
- `revealed` (object, required, nullable): Generated secrets (webhook signing secret). Shown only now.

```json
{
  "connection": {
    "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "connector": "string",
    "name": "Notes",
    "authMethod": "token",
    "settings": {},
    "credentialsHint": null,
    "account": null,
    "status": "active",
    "lastError": null,
    "lastValidatedAt": null,
    "createdBy": null,
    "updatedBy": null,
    "createdAt": "2026-11-12T09:30:00.000Z",
    "updatedAt": "2026-11-12T09:30:00.000Z"
  },
  "warnings": [
    "string"
  ],
  "revealed": null
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Start connecting with OAuth

Source: https://developers.lydie.co/api/publishing/start-connecting-with-oauth

`POST /v1/workspaces/{workspaceId}/connections/authorize`

Returns the provider's sign-in URL. After the person approves, the provider returns to the API, which creates the connection (or re-authorises `connectionId`) and redirects to the web app's connection settings with `?connection=<id>` or `?error=`. Owners and admins only.

Scope: `docs:write`.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/connections/authorize" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "connector": "string",
    "name": "Notes"
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `connector` (string, required): (≥ 1 chars)
- `name` (string, required): (1–120 chars)
- `settings` (object, optional): Default: `{}`.
- `connectionId` (ULID, optional, nullable): Default: `null`.

## Response

- `authorizeUrl` (string, required)
- `expiresAt` (timestamp, required)

```json
{
  "authorizeUrl": "string",
  "expiresAt": "2026-11-12T09:30:00.000Z"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List publications

Source: https://developers.lydie.co/api/publishing/list-publications

`GET /v1/workspaces/{workspaceId}/publications`

Publications in a workspace the caller can see (view access to the published document), optionally of one document.

Scope: `docs:read`.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/publications" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Query parameters

- `documentId` (ULID, optional)

## Response

- `publications` (Publication[], required)
  - `id` (ULID, required)
  - `workspaceId` (string, required): (1–64 chars)
  - `connectionId` (ULID, required)
  - `connector` (string, required)
  - `documentId` (ULID, required)
  - `includeSubpages` (boolean, required)
  - `filter` (object, required, nullable): Publish only documents whose property equals this (lists: contains it).
    - `property` (string, required): (1–128 chars)
    - `equals` (any, required)
  - `config` (object, required)
  - `autoPublish` (boolean, required)
  - `lastRunAt` (timestamp, required, nullable)
  - `items` (PublicationItem[], required)
    - `id` (ULID, required)
    - `documentId` (ULID, required)
    - `state` (string, required): One of: `draft`, `scheduled`, `publishing`, `published`, `updated_pending`, `failed`, `unpublished`, `diverged`.
    - `externalId` (string, required, nullable)
    - `externalUrl` (string, required, nullable)
    - `lastPublishedAt` (timestamp, required, nullable)
    - `lastError` (object, required, nullable)
    - `divergence` (object, required, nullable): For diverged items: reason, base/ours/theirs (destination format), conflicts, marked text and the pull request.
    - `updatedAt` (timestamp, required)
  - `createdBy` (string, required, nullable)
  - `updatedBy` (string, required, nullable)
  - `createdAt` (timestamp, required)
  - `updatedAt` (timestamp, required)

```json
{
  "publications": [
    {
      "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "connectionId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "connector": "string",
      "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
      "includeSubpages": false,
      "filter": null,
      "config": {},
      "autoPublish": false,
      "lastRunAt": null,
      "items": [
        {
          "id": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "documentId": "01JCQ3V5MZ8G4ZK2X7T9R6N1PB",
          "state": "draft",
          "externalId": null,
          "externalUrl": null,
          "lastPublishedAt": null,
          "lastError": null,
          "divergence": null,
          "updatedAt": "2026-11-12T09:30:00.000Z"
        }
      ],
      "createdBy": null,
      "updatedBy": null,
      "createdAt": "2026-11-12T09:30:00.000Z",
      "updatedAt": "2026-11-12T09:30:00.000Z"
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# API tokens

Source: https://developers.lydie.co/api/api-tokens

Personal API tokens. These endpoints need a signed-in session: a token cannot create or list tokens.

## Endpoints

- [Revoke an API token](https://developers.lydie.co/api/api-tokens/revoke-an-api-token.md): `DELETE /v1/api-tokens/{tokenId}`
- [List your API tokens](https://developers.lydie.co/api/api-tokens/list-your-api-tokens.md): `GET /v1/workspaces/{workspaceId}/api-tokens`
- [Create an API token](https://developers.lydie.co/api/api-tokens/create-an-api-token.md): `POST /v1/workspaces/{workspaceId}/api-tokens`

## The ApiToken object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `name` (string, required)
- `prefix` (string, required): The secret's first characters, to recognise it.
- `scopes` (string[], required)
- `createdAt` (string, required)
- `lastUsedAt` (string, required, nullable)
- `expiresAt` (string, required, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "name": "Notes",
  "prefix": "string",
  "scopes": [
    "docs:read"
  ],
  "createdAt": "string",
  "lastUsedAt": null,
  "expiresAt": null
}
```

---

# Revoke an API token

Source: https://developers.lydie.co/api/api-tokens/revoke-an-api-token

`DELETE /v1/api-tokens/{tokenId}`

The token stops working at once.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/api-tokens/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `tokenId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List your API tokens

Source: https://developers.lydie.co/api/api-tokens/list-your-api-tokens

`GET /v1/workspaces/{workspaceId}/api-tokens`

Your live (not revoked, not expired) tokens for a workspace, newest first.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/api-tokens" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `tokens` (ApiToken[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `name` (string, required)
  - `prefix` (string, required): The secret's first characters, to recognise it.
  - `scopes` (string[], required)
  - `createdAt` (string, required)
  - `lastUsedAt` (string, required, nullable)
  - `expiresAt` (string, required, nullable)

```json
{
  "tokens": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "name": "Notes",
      "prefix": "string",
      "scopes": [
        "docs:read"
      ],
      "createdAt": "string",
      "lastUsedAt": null,
      "expiresAt": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Create an API token

Source: https://developers.lydie.co/api/api-tokens/create-an-api-token

`POST /v1/workspaces/{workspaceId}/api-tokens`

Creates a personal API token for one workspace. The secret is returned once; send it as `Authorization: Bearer <secret>` to /v1 operation routes or /mcp. It acts as you, limited to this workspace and the given scopes (default: read and write).

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X POST "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/api-tokens" \
  -H "Authorization: Bearer $LYDIE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sync script",
    "scopes": [
      "docs:read"
    ]
  }'
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Body

- `name` (string, required): (1–100 chars)
- `scopes` (string[], optional): Default: `["docs:read","docs:write"]`. (≥ 1 items)
- `expiresInDays` (integer, optional): (1–3650)

## Response

- `token` (ApiToken, required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `name` (string, required)
  - `prefix` (string, required): The secret's first characters, to recognise it.
  - `scopes` (string[], required)
  - `createdAt` (string, required)
  - `lastUsedAt` (string, required, nullable)
  - `expiresAt` (string, required, nullable)
- `secret` (string, required)

```json
{
  "token": {
    "id": "string",
    "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
    "name": "Notes",
    "prefix": "string",
    "scopes": [
      "docs:read"
    ],
    "createdAt": "string",
    "lastUsedAt": null,
    "expiresAt": null
  },
  "secret": "string"
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# Connected apps

Source: https://developers.lydie.co/api/connected-apps

Apps you allowed through OAuth, such as MCP clients. Signed-in session only.

## Endpoints

- [Disconnect an app](https://developers.lydie.co/api/connected-apps/disconnect-an-app.md): `DELETE /v1/oauth-grants/{grantId}`
- [List connected apps](https://developers.lydie.co/api/connected-apps/list-connected-apps.md): `GET /v1/workspaces/{workspaceId}/oauth-grants`

## The OAuthGrant object

- `id` (string, required): (1–64 chars)
- `workspaceId` (string, required): (1–64 chars)
- `client` (object, required)
  - `id` (string, required)
  - `name` (string, required)
  - `uri` (string, optional)
- `scopes` (string[], required)
- `createdAt` (string, required)
- `lastUsedAt` (string, required, nullable)

```json
{
  "id": "string",
  "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
  "client": {
    "id": "string",
    "name": "Notes",
    "uri": "string"
  },
  "scopes": [
    "docs:read"
  ],
  "createdAt": "string",
  "lastUsedAt": null
}
```

---

# Disconnect an app

Source: https://developers.lydie.co/api/connected-apps/disconnect-an-app

`DELETE /v1/oauth-grants/{grantId}`

Its access and refresh tokens stop working at once.

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl -X DELETE "https://api.lydie.co/v1/oauth-grants/01JCQ3V5MZ8G4ZK2X7T9R6N1PB" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `grantId` (string, required): (1–64 chars)

## Response

- `ok` (true, required)

```json
{
  "ok": true
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.

---

# List connected apps

Source: https://developers.lydie.co/api/connected-apps/list-connected-apps

`GET /v1/workspaces/{workspaceId}/oauth-grants`

Apps you allowed to act for you in this workspace through OAuth (MCP clients).

Needs a signed-in session; API and OAuth tokens get 403.

## Request

```bash
curl "https://api.lydie.co/v1/workspaces/01JCQ3TZ0WJ8K4M2X7T9R6N1PA/oauth-grants" \
  -H "Authorization: Bearer $LYDIE_TOKEN"
```

## Path parameters

- `workspaceId` (string, required): (1–64 chars)

## Response

- `grants` (OAuthGrant[], required)
  - `id` (string, required): (1–64 chars)
  - `workspaceId` (string, required): (1–64 chars)
  - `client` (object, required)
    - `id` (string, required)
    - `name` (string, required)
    - `uri` (string, optional)
  - `scopes` (string[], required)
  - `createdAt` (string, required)
  - `lastUsedAt` (string, required, nullable)

```json
{
  "grants": [
    {
      "id": "string",
      "workspaceId": "01JCQ3TZ0WJ8K4M2X7T9R6N1PA",
      "client": {
        "id": "string",
        "name": "Notes",
        "uri": "string"
      },
      "scopes": [
        "docs:read"
      ],
      "createdAt": "string",
      "lastUsedAt": null
    }
  ]
}
```

Errors use the envelope described at https://developers.lydie.co/errors.md.
