Document Command API

Execute Commands on Documents

Required scope: public-api:write

Description

Execute a Document Command based on its id. All commands run in a single transaction.
Curl Example
ACCESS_TOKEN=ey1234
curl -k -X PATCH "https://server.livingdocs.io/api/v1/documents/:id/commands" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  --data-binary @- << EOF
  {
    "commands": [{
      "operation": "setMetadataProperty",
      "propertyName": "title",
      "value": "updated title"
    }]
  }
EOF

Endpoint

PATCH api/v1/documents/:id/commands

Parameters

NameTypeRequiredNotes
versionintegerCurrent document version. When set on update the version is checked.
preconditionsarrayAn 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.
commandsarrayxAn array of commands to execute. Each entry is an object with at least an operation property.

Possible operations:
- setMetadataProperty
- setTitle
- insertComponent Added in: release-2024-05
- removeComponent Added in: release-2024-07
- setComponentCondition Added in: release-2024-11
- setComponentStyle Added in: release-2024-11
- setEditableDirective
- setIncludeDirective Added in: release-2024-11
- setLinkDirective Added in: release-2024-11
- setStyleDirective Added in: release-2024-11
- publish
- unpublish Added in: 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

{
  "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"
    },
    {
      // Creates a new publication for the document if applicable
      "operation": "publish"
    },
    {
      // Unpublishes the document if it was published before.
      // Cannot be used with "publish" command in same request.
      "operation": "unpublish"
    }
  ]
}

Response

204
api/v1/documents/:id/commands
{
  "status": 204
}
400
Bad Request
api/v1/documents/:id/commands
{
  "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/v1/documents/:id/commands
{
  "status": 404,
  "error": "Not Found",
  "error_details": {
    "name": "NotFound",
    "message": "Document Not Found"
  }
}
409
Conflict
api/v1/documents/:id/commands
{
  "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'"
  }
}