---
title: Document Command API
---
## Execute Commands on Documents
**Required scope:** `public-api:write`
Execute a Document Command based on its `id`.
All commands run in a single transaction.
**History**
| Version | Change |
| ------- | ------ |
| release-2026-03 | Added `preserveUpdatedAt` parameter. When set to `true`, the document's `updated_at` timestamp is not modified. This is useful for imports and migrations where the original timestamps should be preserved. |
| release-2025-07 | The following commands got added: `setEmbargo`, `removeEmbargo`, `addPublishSchedule`, `cancelPublishSchedule`, `addUnpublishSchedule`, `cancelUnpublishSchedule`. |
| release-2024-11 | The following commands got added: `setComponentCondition`, `setComponentStyle`, `setIncludeDirective`, `setLinkDirective`, `setStyleDirective`. |
| release-2024-07 | The following commands got added: `removeComponent`, `unpublish`. |
| release-2024-05 | The following commands got added: `insertComponent`. |
| release-2024-03 | A new `precondition` named `isPublishedAndHasNoChanges` has been added. |
| release-2023-11 | Initial support. |
**Curl Example**
```bash
ACCESS_TOKEN=ey1234
curl -k -X PATCH "https://server.livingdocs.io/api/2026-05/documents/{documentId}/commands" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-binary @- << EOF
{
"commands": [{
"operation": "setMetadataProperty",
"propertyName": "title",
"value": "updated title"
}]
}
EOF
```
**Endpoint**
```http
PATCH /api/2026-05/documents/{documentId}/commands
```
**Parameters**
| Name | Type | Required | Notes |
| ---- | ---- | :------: | ----- |
| version | integer | | Current document version. When set on update the version is checked. |
| preserveUpdatedAt | boolean | | When set to `true`, the document's `updated_at` timestamp is not modified by the command execution. By default (`false`), `updated_at` is set to the current time.
When combined with a `publish` command, the `lastPublicationDate` will also be set to the preserved `updated_at` timestamp instead of the current time.
This is useful for imports and migrations where the original timestamps should be preserved to maintain correct dashboard sort order. |
| preconditions | array | | An array of preconditions for command execution. If a precondition assertion fails, no commands are executed and the request responds with a `429 Conflict` status.
Each entry is an object with at least a **type** property.
Possible types:
- `isPublished`: Document is currently public
- `isPublishedAndHasNoChanges`: Document is currently public and has no changes since last publish
See further details in example requests. |
| commands | array | x | An array of commands to execute. Each entry is an object with at least an **operation** property.
Command API operations `publish`, `unpublish`, and `addPublishSchedule` can only be used as the last operation in a request and are mutually exclusive.
Possible operations:
- `setMetadataProperty`
- `setTitle`
- `insertComponent` Added in: [`release-2024-05`](/operations/releases/release-2024-05/)
- `removeComponent` Added in: [`release-2024-07`](/operations/releases/release-2024-07/)
- `setComponentCondition` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setComponentStyle` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setEditableDirective`
- `setIncludeDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setLinkDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setStyleDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setEmbargo` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `removeEmbargo` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `addPublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `cancelPublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `addUnpublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `cancelUnpublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `publish`
- `unpublish` Added in: [`release-2024-07`](/operations/releases/release-2024-07/)
Some commands supports an optional `oldValue` parameter. When specified, the system verifies that the value being updated matches the provided `oldValue`. This prevents accidental overwrites that might occur due to changes made between reading a document and issuing the command. If the `oldValue` does not match, a conflict error is thrown. `oldValue` is redundant when providing a document version.
See further details in example requests. |
**Example Request**
```js
{
"version": 1,
// When true, the document's updated_at timestamp is preserved
"preserveUpdatedAt": true,
"preconditions": [
// Asserts that the document is published or
// unpublished based on the value property.
{"type": "isPublished", "value": true}
// Asserts that the document is published and
// has no changes since last publish.
// {"type": "isPublishedAndHasNoChanges"}
],
"commands": [
{
// Update a single metadata property.
"operation": "setMetadataProperty",
"propertyName": "title",
"value": "updated title", // send null to delete metadata property
"oldValue": "previous title" // optional, for conflict detection (not necessary when sending document version too)
},
{
// Sets the title property on a document (might be overruled by displayTitlePattern on read).
"operation": "setTitle",
"value": "updated title",
"oldValue": "previous title"
},
{
// Inserts a new component into the document content.
"operation": "insertComponent",
"componentId": "doc-custom-123456",
"componentName": "paragraph",
"content": {
"text": "Some text"
},
"position": {
"parentComponentId": "doc-4a2b3g4d5", // Omit to insert into document root
"parentContainerName": "children", // Omit to insert into document root,
"previousComponentId": "doc-1a2b3c4d5", // To insert after component with this id
"nextComponentId": "doc-1a2b3c4d5", // To insert before component with this id
}
},
{
// Removes a component from the document content.
// Does not work if component or parent component has `position: 'fixed'`
"operation": "removeComponent",
"componentId": "doc-4a2b3g4d5"
},
{
// Updates a component condition. Currently, only "dateTime" conditions
// are supported.
"operation": "setComponentCondition",
"componentId": "doc-123",
"conditionName": "dateTime",
"value": {
"gte": "2025-01-01T10:30:00.000Z",
"lt": "2025-02-02T14:30:00.000Z"
},
"oldValue": {
"gte": "2024-01-01T10:30:00.000Z",
"lt": "2024-02-02T14:30:00.000Z"
}
},
{
// Updates a component style. It supports all types: style, option, and select.
"operation": "setComponentStyle",
"componentId": "doc-123",
"propertyName": "background",
"value": "#1fc47a",
"oldValue": "#000"
},
{
// Sets the content of an editable directive.
"operation": "setEditableDirective",
"componentId": "doc-1a2b3c4d5",
"directiveName": "headline",
"value": "updated headline"
},
{
// Updates params and overrides of an include directive. These properties
// depend on each other: if only params are provided, any existing
// overrides are removed. Conversely, specifying overrides without params
// is invalid and will return a validation error. To update overrides,
// both the params and overrides properties must be provided.
"operation": "setIncludeDirective",
"componentId": "doc-123",
"directiveName": "related-article",
"value": {
"params": {
"teaser": {
"$ref": "document",
"reference": {"id": "3"}
}
},
"overrides": [{
"id": "teaser-normal-3",
"content": {
"link": {"href": "https://livingdocs.io"},
"title": "Changed title"
},
"originalSnapshot": {},
"contentProperties": []
}]
},
"oldValue": null
},
{
// Updates a link directive.
"operation": "setLinkDirective",
"componentId": "doc-123",
"directiveName": "link",
"value": {
"href": "https://livingdocs.io/article/123",
"target": "_blank",
"$ref": "document",
"reference": {"id": "123"}
},
"oldValue": {
"href": "https://livingdocs.io/"
}
},
{
// Updates a style directive. It supports all types: style, option, and select.
"operation": "setStyleDirective",
"componentId": "doc-123",
"directiveName": "appearance",
"propertyName": "background",
"value": "#1fc47a",
"oldValue": "#000"
},
{
// Adds an embargo
"operation": "setEmbargo",
"reason": "Some reason", // optional
"until": "2021-11-04T00:00:00Z" // optional
},
{
// Removes an embargo
"operation": "removeEmbargo"
},
{
// Adds a publish schedule. Can only be the last command in a request.
// Therefore, it cannot be used with "publish" or "unpublish".
"operation": "addPublishSchedule",
"date": "2021-11-04T00:00:00Z"
},
{
// Removes a publish schedule
"operation": "cancelPublishSchedule"
},
{
// Adds a unpublish schedule
"operation": 'addUnpublishSchedule',
"date": "2021-11-04T00:00:00Z"
},
{
// Removes a unpublish schedule
"operation": "cancelUnpublishSchedule"
}
{
// Creates a new publication for the document if applicable. Can only
// be the last command in a request. Therefore, it cannot be used with
// "addPublishSchedule" or "unpublish".
"operation": "publish"
},
{
// Unpublishes the document if it was published before. Can only be the
// last command in a request. Therefore, it cannot be used with
// "addPublishSchedule" or "publish".
"operation": "unpublish"
}
]
}
```
**Response**
_204 OK_ — `/api/2026-05/documents/{documentId}/commands`
```txt
No Content
```
_400 Bad Request_ — `/api/2026-05/documents/{documentId}/commands`
```json
{
"status": 400,
"error": "Bad Request",
"error_details": {
"commands.0": "value of tag \"operation\" must be in oneOf"
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"commands.0.value": "must match exactly one schema in oneOf",
"commands.0.value.params": "Missing required property: params"
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Metadata property \"notExistingProperty\" does not exist",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Component 'doc-123' does not exist in document '123'",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Directive 'my-directive' of type 'editable' does not exist on component 'doc-123' in document '123'",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Include validation failed: {\"title\":\"Invalid type: expected string\",\"teasers.limit\":\"Missing required property: limit\",\"teasers.invalid\":\"Additional properties not allowed\"}",
"commandIndex": 0
}
}
```
_404 Not Found_ — `/api/2026-05/documents/{documentId}/commands`
```json
{
"status": 404,
"error": "Not Found",
"error_details": {
"name": "NotFound",
"message": "Document Not Found"
}
}
```
_409 Conflict_ — `/api/2026-05/documents/{documentId}/commands`
```json
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "The document you tried to update is outdated",
"expectedVersion": 1,
"currentVersion": 2
}
}
// or
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "Precondition failed: 'isPublished'"
}
}
// or
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "Cannot update outdated value'"
}
}
```
## Execute Commands on Documents
> [!NOTE]
> This endpoint has changes in version 2026-03.
>
**Required scope:** `public-api:write`
Execute a Document Command based on its `id`.
All commands run in a single transaction.
**History**
| Version | Change |
| ------- | ------ |
| release-2025-07 | The following commands got added: `setEmbargo`, `removeEmbargo`, `addPublishSchedule`, `cancelPublishSchedule`, `addUnpublishSchedule`, `cancelUnpublishSchedule`. |
| release-2024-11 | The following commands got added: `setComponentCondition`, `setComponentStyle`, `setIncludeDirective`, `setLinkDirective`, `setStyleDirective`. |
| release-2024-07 | The following commands got added: `removeComponent`, `unpublish`. |
| release-2024-05 | The following commands got added: `insertComponent`. |
| release-2024-03 | A new `precondition` named `isPublishedAndHasNoChanges` has been added. |
| release-2023-11 | Initial support. |
**Curl Example**
```bash
ACCESS_TOKEN=ey1234
curl -k -X PATCH "https://server.livingdocs.io/api/2026-01/documents/{documentId}/commands" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-binary @- << EOF
{
"commands": [{
"operation": "setMetadataProperty",
"propertyName": "title",
"value": "updated title"
}]
}
EOF
```
**Endpoint**
```http
PATCH /api/2026-01/documents/{documentId}/commands
```
**Parameters**
| Name | Type | Required | Notes |
| ---- | ---- | :------: | ----- |
| version | integer | | Current document version. When set on update the version is checked. |
| preconditions | array | | An array of preconditions for command execution. If a precondition assertion fails, no commands are executed and the request responds with a `429 Conflict` status.
Each entry is an object with at least a **type** property.
Possible types:
- `isPublished`: Document is currently public
- `isPublishedAndHasNoChanges`: Document is currently public and has no changes since last publish
See further details in example requests. |
| commands | array | x | An array of commands to execute. Each entry is an object with at least an **operation** property.
Command API operations `publish`, `unpublish`, and `addPublishSchedule` can only be used as the last operation in a request and are mutually exclusive.
Possible operations:
- `setMetadataProperty`
- `setTitle`
- `insertComponent` Added in: [`release-2024-05`](/operations/releases/release-2024-05/)
- `removeComponent` Added in: [`release-2024-07`](/operations/releases/release-2024-07/)
- `setComponentCondition` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setComponentStyle` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setEditableDirective`
- `setIncludeDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setLinkDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setStyleDirective` Added in: [`release-2024-11`](/operations/releases/release-2024-11/)
- `setEmbargo` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `removeEmbargo` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `addPublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `cancelPublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `addUnpublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `cancelUnpublishSchedule` Added in: [`release-2025-07`](/operations/releases/release-2025-07/)
- `publish`
- `unpublish` Added in: [`release-2024-07`](/operations/releases/release-2024-07/)
Some commands supports an optional `oldValue` parameter. When specified, the system verifies that the value being updated matches the provided `oldValue`. This prevents accidental overwrites that might occur due to changes made between reading a document and issuing the command. If the `oldValue` does not match, a conflict error is thrown. `oldValue` is redundant when providing a document version.
See further details in example requests. |
**Example Request**
```js
{
"version": 1,
"preconditions": [
// Asserts that the document is published or
// unpublished based on the value property.
{"type": "isPublished", "value": true}
// Asserts that the document is published and
// has no changes since last publish.
// {"type": "isPublishedAndHasNoChanges"}
],
"commands": [
{
// Update a single metadata property.
"operation": "setMetadataProperty",
"propertyName": "title",
"value": "updated title", // send null to delete metadata property
"oldValue": "previous title" // optional, for conflict detection (not necessary when sending document version too)
},
{
// Sets the title property on a document (might be overruled by displayTitlePattern on read).
"operation": "setTitle",
"value": "updated title",
"oldValue": "previous title"
},
{
// Inserts a new component into the document content.
"operation": "insertComponent",
"componentId": "doc-custom-123456",
"componentName": "paragraph",
"content": {
"text": "Some text"
},
"position": {
"parentComponentId": "doc-4a2b3g4d5", // Omit to insert into document root
"parentContainerName": "children", // Omit to insert into document root,
"previousComponentId": "doc-1a2b3c4d5", // To insert after component with this id
"nextComponentId": "doc-1a2b3c4d5", // To insert before component with this id
}
},
{
// Removes a component from the document content.
// Does not work if component or parent component has `position: 'fixed'`
"operation": "removeComponent",
"componentId": "doc-4a2b3g4d5"
},
{
// Updates a component condition. Currently, only "dateTime" conditions
// are supported.
"operation": "setComponentCondition",
"componentId": "doc-123",
"conditionName": "dateTime",
"value": {
"gte": "2025-01-01T10:30:00.000Z",
"lt": "2025-02-02T14:30:00.000Z"
},
"oldValue": {
"gte": "2024-01-01T10:30:00.000Z",
"lt": "2024-02-02T14:30:00.000Z"
}
},
{
// Updates a component style. It supports all types: style, option, and select.
"operation": "setComponentStyle",
"componentId": "doc-123",
"propertyName": "background",
"value": "#1fc47a",
"oldValue": "#000"
},
{
// Sets the content of an editable directive.
"operation": "setEditableDirective",
"componentId": "doc-1a2b3c4d5",
"directiveName": "headline",
"value": "updated headline"
},
{
// Updates params and overrides of an include directive. These properties
// depend on each other: if only params are provided, any existing
// overrides are removed. Conversely, specifying overrides without params
// is invalid and will return a validation error. To update overrides,
// both the params and overrides properties must be provided.
"operation": "setIncludeDirective",
"componentId": "doc-123",
"directiveName": "related-article",
"value": {
"params": {
"teaser": {
"$ref": "document",
"reference": {"id": "3"}
}
},
"overrides": [{
"id": "teaser-normal-3",
"content": {
"link": {"href": "https://livingdocs.io"},
"title": "Changed title"
},
"originalSnapshot": {},
"contentProperties": []
}]
},
"oldValue": null
},
{
// Updates a link directive.
"operation": "setLinkDirective",
"componentId": "doc-123",
"directiveName": "link",
"value": {
"href": "https://livingdocs.io/article/123",
"target": "_blank",
"$ref": "document",
"reference": {"id": "123"}
},
"oldValue": {
"href": "https://livingdocs.io/"
}
},
{
// Updates a style directive. It supports all types: style, option, and select.
"operation": "setStyleDirective",
"componentId": "doc-123",
"directiveName": "appearance",
"propertyName": "background",
"value": "#1fc47a",
"oldValue": "#000"
},
{
// Adds an embargo
"operation": "setEmbargo",
"reason": "Some reason", // optional
"until": "2021-11-04T00:00:00Z" // optional
},
{
// Removes an embargo
"operation": "removeEmbargo"
},
{
// Adds a publish schedule. Can only be the last command in a request.
// Therefore, it cannot be used with "publish" or "unpublish".
"operation": "addPublishSchedule",
"date": "2021-11-04T00:00:00Z"
},
{
// Removes a publish schedule
"operation": "cancelPublishSchedule"
},
{
// Adds a unpublish schedule
"operation": 'addUnpublishSchedule',
"date": "2021-11-04T00:00:00Z"
},
{
// Removes a unpublish schedule
"operation": "cancelUnpublishSchedule"
}
{
// Creates a new publication for the document if applicable. Can only
// be the last command in a request. Therefore, it cannot be used with
// "addPublishSchedule" or "unpublish".
"operation": "publish"
},
{
// Unpublishes the document if it was published before. Can only be the
// last command in a request. Therefore, it cannot be used with
// "addPublishSchedule" or "publish".
"operation": "unpublish"
}
]
}
```
**Response**
_204 OK_ — `/api/2026-01/documents/{documentId}/commands`
```txt
No Content
```
_400 Bad Request_ — `/api/2026-01/documents/{documentId}/commands`
```json
{
"status": 400,
"error": "Bad Request",
"error_details": {
"commands.0": "value of tag \"operation\" must be in oneOf"
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"commands.0.value": "must match exactly one schema in oneOf",
"commands.0.value.params": "Missing required property: params"
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Metadata property \"notExistingProperty\" does not exist",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Component 'doc-123' does not exist in document '123'",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Directive 'my-directive' of type 'editable' does not exist on component 'doc-123' in document '123'",
"commandIndex": 0
}
}
// or
{
"status": 400,
"error": "Bad Request",
"error_details": {
"message": "Command at index 0 failed: Include validation failed: {\"title\":\"Invalid type: expected string\",\"teasers.limit\":\"Missing required property: limit\",\"teasers.invalid\":\"Additional properties not allowed\"}",
"commandIndex": 0
}
}
```
_404 Not Found_ — `/api/2026-01/documents/{documentId}/commands`
```json
{
"status": 404,
"error": "Not Found",
"error_details": {
"name": "NotFound",
"message": "Document Not Found"
}
}
```
_409 Conflict_ — `/api/2026-01/documents/{documentId}/commands`
```json
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "The document you tried to update is outdated",
"expectedVersion": 1,
"currentVersion": 2
}
}
// or
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "Precondition failed: 'isPublished'"
}
}
// or
{
"status": 409,
"error": "Conflict",
"error_details": {
"name": "Conflict",
"message": "Cannot update outdated value'"
}
}
```