diff --git a/content/guides/editor/menus/index.md b/content/guides/editor/menus/index.md index 39058d76e..956018384 100644 --- a/content/guides/editor/menus/index.md +++ b/content/guides/editor/menus/index.md @@ -4,9 +4,8 @@ description: Model menus with data records weight: 4 --- -{{< info >}} -As of {{< release "release-2024-11" >}}, the Menu Tool has been deprecated in favor of modeling menus with data records. Please reach out for assistance with migrating from the Menu Tool to data records. -{{< /info >}} +>[!WARNING] {{< deprecated-in "release-2024-11" >}} +The Menu Tool has been deprecated in favor of modeling menus with data records. Please reach out for assistance with migrating from the Menu Tool to data records. Menus can be conveniently modeled using data records, which can be included in dashboards and referenced in other documents. Like all documents in Livingdocs, they define the content but not the presentation. @@ -146,4 +145,4 @@ const filters = JSON.stringify([ {key: 'metadata.name.id', term: 'menu:main'} ]) const response = await fetch(`api/v1/publications/search?filters=${filters}`) -``` \ No newline at end of file +``` diff --git a/content/operations/releases/release-2022-09.md b/content/operations/releases/release-2022-09.md index 1b556f6fa..50bd74a70 100644 --- a/content/operations/releases/release-2022-09.md +++ b/content/operations/releases/release-2022-09.md @@ -5,7 +5,6 @@ description: Release notes for release-2022-09 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2022-09/ - /operations/releases/release-2022-09/release-2022-09/ --- diff --git a/content/operations/releases/release-2022-11.md b/content/operations/releases/release-2022-11.md index c323abebb..9aec8f624 100644 --- a/content/operations/releases/release-2022-11.md +++ b/content/operations/releases/release-2022-11.md @@ -5,7 +5,6 @@ description: Release notes for release-2022-11 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2022-11/ - /operations/releases/release-2022-11/release-2022-11/ --- diff --git a/content/operations/releases/release-2023-01.md b/content/operations/releases/release-2023-01.md index 82f83820a..1461ad2b2 100644 --- a/content/operations/releases/release-2023-01.md +++ b/content/operations/releases/release-2023-01.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-01 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-01/ - /operations/releases/release-2023-01/release-2023-01/ --- diff --git a/content/operations/releases/release-2023-03.md b/content/operations/releases/release-2023-03.md index 0d4de8757..6068fa662 100644 --- a/content/operations/releases/release-2023-03.md +++ b/content/operations/releases/release-2023-03.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-03 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-03/ - /operations/releases/release-2023-03/release-2023-03/ --- diff --git a/content/operations/releases/release-2023-05.md b/content/operations/releases/release-2023-05.md index 621f01865..c2414ea59 100644 --- a/content/operations/releases/release-2023-05.md +++ b/content/operations/releases/release-2023-05.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-05 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-05/ - /operations/releases/release-2023-05/release-2023-05/ --- diff --git a/content/operations/releases/release-2023-07.md b/content/operations/releases/release-2023-07.md index 04f9cb30e..84f1b55a1 100644 --- a/content/operations/releases/release-2023-07.md +++ b/content/operations/releases/release-2023-07.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-07 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-07/ - /operations/releases/release-2023-07/release-2023-07/ --- diff --git a/content/operations/releases/release-2023-09.md b/content/operations/releases/release-2023-09.md index 65d956fc0..f52d85580 100644 --- a/content/operations/releases/release-2023-09.md +++ b/content/operations/releases/release-2023-09.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-09 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-09/ - /operations/releases/release-2023-09/release-2023-09/ --- diff --git a/content/operations/releases/release-2023-11.md b/content/operations/releases/release-2023-11.md index 93363b153..82cb3f025 100644 --- a/content/operations/releases/release-2023-11.md +++ b/content/operations/releases/release-2023-11.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2023-11 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2023-11/ - /operations/releases/release-2023-11/release-2023-11/ --- diff --git a/content/operations/releases/release-2024-01.md b/content/operations/releases/release-2024-01.md index 1cb582aa3..919325ea6 100644 --- a/content/operations/releases/release-2024-01.md +++ b/content/operations/releases/release-2024-01.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2024-01 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2024-01/ - /operations/releases/release-2024-01/release-2024-01/ --- diff --git a/content/operations/releases/release-2024-03.md b/content/operations/releases/release-2024-03.md index 51f470c35..7671f6184 100644 --- a/content/operations/releases/release-2024-03.md +++ b/content/operations/releases/release-2024-03.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2024-03 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2024-03/ - /operations/releases/release-2024-03/release-2024-03/ --- diff --git a/content/operations/releases/release-2024-05.md b/content/operations/releases/release-2024-05.md index 869cf5966..2c5a92464 100644 --- a/content/operations/releases/release-2024-05.md +++ b/content/operations/releases/release-2024-05.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2024-05 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2024-05/ - /operations/releases/release-2024-05/release-2024-05/ --- diff --git a/content/operations/releases/release-2024-07.md b/content/operations/releases/release-2024-07.md index c43e6130d..81dca8ca9 100644 --- a/content/operations/releases/release-2024-07.md +++ b/content/operations/releases/release-2024-07.md @@ -5,7 +5,6 @@ description: Technical Release Notes for release-2024-07 excludeFromSearch: false hideSectionTeaser: true aliases: - - /operations/releases/release-2024-07/ - /operations/releases/release-2024-07/release-2024-07/ --- diff --git a/content/operations/releases/release-2024-09.md b/content/operations/releases/release-2024-09.md index ca4af62f2..cbc11aff4 100644 --- a/content/operations/releases/release-2024-09.md +++ b/content/operations/releases/release-2024-09.md @@ -4,8 +4,6 @@ title: September 2024 Release description: Technical Release Notes for release-2024-09 excludeFromSearch: false hideSectionTeaser: true -aliases: - - /operations/releases/release-2024-09/ --- {{< release-header diff --git a/content/operations/releases/release-2024-11.md b/content/operations/releases/release-2024-11.md index 8042e13da..0f4c8f464 100644 --- a/content/operations/releases/release-2024-11.md +++ b/content/operations/releases/release-2024-11.md @@ -4,8 +4,6 @@ title: November 2024 Release description: Technical Release Notes for release-2024-11 excludeFromSearch: false hideSectionTeaser: true -aliases: - - /operations/releases/release-2024-11/ --- {{< release-header diff --git a/content/operations/releases/release-2025-01.md b/content/operations/releases/release-2025-01.md index e13748790..d7645a05e 100644 --- a/content/operations/releases/release-2025-01.md +++ b/content/operations/releases/release-2025-01.md @@ -4,8 +4,6 @@ title: January 2025 Release description: Technical Release Notes for release-2025-01 excludeFromSearch: true hideSectionTeaser: true -aliases: - - /operations/releases/release-2025-01/ --- {{< release-header diff --git a/content/reference/public-api/add-delivery-status.md b/content/reference/public-api/add-delivery-status.md index 663228de6..8afaef1d9 100644 --- a/content/reference/public-api/add-delivery-status.md +++ b/content/reference/public-api/add-delivery-status.md @@ -8,57 +8,4 @@ menus: parent: Public API --- -{{< api-example - title="Add Delivery Status" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/documents/:documentId/addDeliveryStatus" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "reportId": "2SG2MAA9RwPn", - "publicationId": 524, - "deliveryHandle": "web", - "status": "success", - "message": "Message with html" - } -EOF -``` - ---endpoint-- -``` -POST api/v1/documents/:documentId/addDeliveryStatus -``` - ---parameters-- -| Name | Type | Required | Notes | -|----------------|---------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| :documentId | integer | x | | -| reportId | string | | If provided, this will update the matching delivery build; otherwise, it will create a new one. | -| publicationId | integer | (x) | Required for delivery builds of type `publication` | -| deliveryHandle | string | x | | -| status | string | x | One of: "success", "failed", "aborted" ({{< added-in "release-2024-07" >}}), "in-progress" | -| message | string | | String or sanitized HTML (supports ``, ``, `` and `
` tags) | -| userChoices | Array<{label: string, value: string}> | | An array of options given to the user to choose from. This parameter is only allowed when `status` is set to "in-progress". ({{< added-in "release-2024-07" >}}) | - ---description-- -This endpoint allows an external system to send updates about a delivery build to Livingdocs. - -Delivery builds are initiated by users within the Livingdocs editor and can be configured to notify an external system. Through this endpoint, external systems can report back to Livingdocs regarding the status of a triggered task or request further clarification by providing user choices. For more information on how to set up and use delivery builds, please refer to our [guide]({{< ref "/guides/editor/publish-control/delivery" >}}). - ---response-- -200 ---- -api/v1/documents/222/addDeliveryStatus ---- -```js -{reportId: '0TAW2ORdNjuM'} -``` - -{{< /api-example >}} +{{< api-example-resource file="add-delivery-status.yaml" >}} diff --git a/content/reference/public-api/add-delivery-status.yaml b/content/reference/public-api/add-delivery-status.yaml new file mode 100644 index 000000000..e4f59cec0 --- /dev/null +++ b/content/reference/public-api/add-delivery-status.yaml @@ -0,0 +1,64 @@ +title: Add Delivery Status +description: | + This endpoint allows an external system to send updates about a delivery build to Livingdocs. + + Delivery builds are initiated by users within the Livingdocs editor and can be configured to notify an external system. Through this endpoint, external systems can report back to Livingdocs regarding the status of a triggered task or request further clarification by providing user choices. For more information on how to set up and use delivery builds, please refer to our [guide]({{< ref "/guides/editor/publish-control/delivery" >}}). + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/documents/:documentId/addDeliveryStatus" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "reportId": "2SG2MAA9RwPn", + "publicationId": 524, + "deliveryHandle": "web", + "status": "success", + "message": "Message with html" + } + EOF +endpoint: + method: POST + path: /api/v1/documents/:documentId/addDeliveryStatus +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: reportId + type: string + required: false + notes: "If provided, this will update the matching delivery build; otherwise, it will create a new one." + - name: publicationId + type: integer + required: conditional + notes: "Required for delivery builds of type `publication`" + - name: deliveryHandle + type: string + required: true + notes: "" + - name: status + type: string + required: true + notes: | + One of: `success`, `failed`, `aborted` ({{< added-in "release-2024-07" >}}), `in-progress` + - name: message + type: string + required: false + notes: "String or sanitized HTML (supports ``, ``, `
` and `
` tags)" + - name: userChoices + type: | + Array<{label: string, value: string}> + required: false + notes: An array of options given to the user to choose from. This parameter is only allowed when `status` is set to `in-progress`. ({{< added-in "release-2024-07" >}}) + +responses: + - code: "200" + name: OK + endpoint: /api/v1/documents/222/addDeliveryStatus + body: | + { + "reportId": "0TAW2ORdNjuM" + } diff --git a/content/reference/public-api/composition-api.md b/content/reference/public-api/composition-api.md index b3178c98f..cfa9aeb9e 100644 --- a/content/reference/public-api/composition-api.md +++ b/content/reference/public-api/composition-api.md @@ -7,160 +7,4 @@ menus: parent: Public API --- -{{< api-example - title="Compose a Publication" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/beta/composition/:documentId" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "fields": ["systemdata", "content", "metadata", "includes", "html"] - } -EOF -``` - ---endpoint-- -``` -POST api/beta/composition/:documentId -``` - ---parameters-- - -|Name|Type|Notes| -|-|-|-| -|fields|array\|A list of the properties which should be computed and returned.
Default: ['systemdata', 'content', 'metadata', 'includes', 'html', 'design']| -|metadata.preload|object|You can pass metadata properties which should be resolved.
This only works for properties of type 'li-document-reference', 'li-document-references', 'li-list-reference' and 'li-tree'
Example: `{metadata: {preload: {myProp: true}}}`| -|resolveIncludes|boolean|Resolve includes. If `true` then 'includes' will be populated and includes will be resolved in the rendered `html`. If 'includes' is added to the fields array as above, they are resolved in a separate array from the content.| -|renderOptions.renderDirectiveInfo|boolean|Add attributes with the directive name to directive elements.| -|ignoreComponentConditions|boolean|Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|componentConditions|string|JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- - -The `Composition API` loads a Publication with all required information to render a whole document with one request. - -##### Advantages - -- Make only one request to get all the required information to render a publication -- High-performing and efficient preloading of references (e.g. lists, includes, other references) -- Useful for a pull architecture -- Deduplication of document teasers: Teasers in `li-document-search` and `li-list-reference` are deduplicated across a document, taking into account teasers from `li-document-reference` and `li-document-references` as well. -- The only endpoint which is able to resolve includes - -##### Related - -- [Latest Publication API]({{< ref "/reference/public-api/publications/latest-publication" >}}) -- [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) - ---response-- -200 ---- ---- -```js -{ - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-18T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-2c95a77x14", - "component": "teaser", - "identifier": "timeline.teaser", - "content": { - "embed-teaser": { - "service": "embed-teaser", - "params": { - "document": { - "$ref": "document", - "reference": { - "id": 7 - } - } - } - } - } - } - ], - "metadata": { - "title": "a title", - "description": "some lead", - "topic": { - "$ref": "document", - "reference": { - "id": "5" - }, - "isPreloaded": true, - "value": { - "metadata": { - "title": "Another title" - }, - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 5, - "contentType": "article", - "documentType": "article", - "publicationId": 7, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-18T17:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - } - } - } - }, - "includes": [ - { - "componentId": "doc-2c95a77x14", - "directiveName": "embed-teaser", - "resolvedValue": { - "content": [ - { - "id": "ref-7", - "component": "p", - "content": { - "text": "Some text." - } - } - ] - } - } - ], - "html": "
...
" -} -``` - -{{< /api-example >}} +{{< api-example-resource file="composition.yaml" >}} diff --git a/content/reference/public-api/composition.yaml b/content/reference/public-api/composition.yaml new file mode 100644 index 000000000..54bab92ce --- /dev/null +++ b/content/reference/public-api/composition.yaml @@ -0,0 +1,172 @@ +title: Compose a Publication +description: | + The `Composition API` loads a Publication with all required information to render a whole document with one request. + + ##### Advantages + - Make only one request to get all the required information to render a publication + - High-performing and efficient preloading of references (e.g. lists, includes, other references) + - Useful for a pull architecture + - Deduplication of document teasers: Teasers in `li-document-search` and `li-list-reference` are deduplicated across a document, taking into account teasers from `li-document-reference` and `li-document-references` as well. + - The only endpoint which is able to resolve includes + + ##### Related + + - [Latest Publication API]({{< ref "/reference/public-api/publications/latest-publication" >}}) + - [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/beta/composition/:documentId" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "fields": ["systemdata", "content", "metadata", "includes", "html"] + } + EOF +endpoint: + method: POST + path: /api/beta/composition/:documentId +parameters: + - name: fields + type: array + required: false + notes: "A list of the properties which should be computed and returned. Default: ['systemdata', 'content', 'metadata', 'includes', 'html', 'design']" + - name: metadata.preload + type: object + required: false + notes: | + You can pass metadata properties which should be resolved. + This only works for properties of type `li-document-reference`, `li-document-references`, `li-list-reference` and `li-tree`. + + Example: `{"metadata": {"preload": {"myProp": true}}}` + + - name: resolveIncludes + type: boolean + required: false + notes: "Resolve includes. If `true` then 'includes' will be populated and includes will be resolved in the rendered `html`. If 'includes' is added to the fields array as above, they are resolved in a separate array from the content." + - name: renderOptions.renderDirectiveInfo + type: boolean + required: false + notes: "Add attributes with the directive name to directive elements." + - name: ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in "release-2024-03" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + - name: componentConditions + type: string + required: false + notes: | + {{< added-in "release-2024-03" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `dateTime: new Date()` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + +responses: + - code: "200" + body: | + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-03-18T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-2c95a77x14", + "component": "teaser", + "identifier": "timeline.teaser", + "content": { + "embed-teaser": { + "service": "embed-teaser", + "params": { + "document": { + "$ref": "document", + "reference": { + "id": 7 + } + } + } + } + } + } + ], + "metadata": { + "title": "a title", + "description": "some lead", + "topic": { + "$ref": "document", + "reference": { + "id": "5" + }, + "isPreloaded": true, + "value": { + "metadata": { + "title": "Another title" + }, + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 5, + "contentType": "article", + "documentType": "article", + "publicationId": 7, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-03-18T17:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + } + } + } + }, + "includes": [ + { + "componentId": "doc-2c95a77x14", + "directiveName": "embed-teaser", + "resolvedValue": { + "content": [ + { + "id": "ref-7", + "component": "p", + "content": { + "text": "Some text." + } + } + ] + } + } + ], + "html": "
...
" + } diff --git a/content/reference/public-api/document-categories.md b/content/reference/public-api/document-categories.md deleted file mode 100644 index f165c2c44..000000000 --- a/content/reference/public-api/document-categories.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: Document Categories -weight: 7 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get a Category with all Information" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/categories/:categoryId" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/categories/:categoryId -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:categoryId|string|x|Id of a specific categories as fetched from the /categories endpoint.| -|?inheritMetadata|boolean||If set to "true" will inherit (but not overwrite) metadata properties from all parents Inheritance depth is limited to 20.| - ---description-- -You need to activate the [Categories]({{< ref "/reference/project-config/categories" >}}) / [Routing]({{< ref "/reference/project-config/content-types#routing" >}}) feature in the Project Config in order to query categories. - - ---response-- -200 ---- -api/v1/categories/123abc ---- -```js -{ - "id": "123abc", - "label": "Sport", - "path": "/sport", - "metadata": { - "adId": "sport-ads", - "analyticsCode": "sport-analytics" - } -} -``` ------ -400 ---- -api/v1/categories/123abc ---- -```js -{ - "status": 400, - "error": "Bad Request", - "error_details": { - "message": "Use of the category API requires a configurable channel. The project you requested uses a static configuration though." - } -} -``` ------ -500 ---- -api/v1/categories/123abc?inheritMetadata=true ---- -```js -{ - "status": 500, - "error": "Bad Request", - "error_details": { - "message": "Inheritance queries can only be made up to a depth of 20." - } -} -``` -{{< /api-example >}} - -{{< api-example - title="Get Categories for a Project" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/categories" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/categories -``` - ---parameters-- - ---description-- -You need to activate the Categories / Routing Feature in the Project Config in order to query categories. ---response-- -200 ---- -api/v1/categories ---- -```js -[ - { - "id": "category-id-1", - "label": "Category 1", - "path": "/category1" - }, - { - "id": "category-id-2", - "label": "Category 2", - "path": "/category2", - "parent": "category-id-1" - }, - { - "id": "category-id-3", - "label": "Category 3", - "path": "/category3" - } -] -``` ------ -400 ---- -api/v1/categories ---- -```js -{ - "status": 400, - "error": "Bad Request", - "error_details": { - "message": "Use of the category API requires a configurable channel. The project you requested uses a static configuration though." - } -} -``` -{{< /api-example >}} diff --git a/content/reference/public-api/document-categories/_index.md b/content/reference/public-api/document-categories/_index.md new file mode 100644 index 000000000..edf2f59fd --- /dev/null +++ b/content/reference/public-api/document-categories/_index.md @@ -0,0 +1,12 @@ +--- +title: Document Categories +weight: 7 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_category.yaml" >}} + +{{< api-example-resource file="get_categories.yaml" >}} diff --git a/content/reference/public-api/document-categories/get_categories.yaml b/content/reference/public-api/document-categories/get_categories.yaml new file mode 100644 index 000000000..7093ebef0 --- /dev/null +++ b/content/reference/public-api/document-categories/get_categories.yaml @@ -0,0 +1,44 @@ +title: Get Categories for a Project +description: | + You need to activate the Categories / Routing Feature in the Project Config in order to query categories. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/categories" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/categories +responses: + - code: "200" + endpoint: /api/v1/categories + body: | + [ + { + "id": "category-id-1", + "label": "Category 1", + "path": "/category1" + }, + { + "id": "category-id-2", + "label": "Category 2", + "path": "/category2", + "parent": "category-id-1" + }, + { + "id": "category-id-3", + "label": "Category 3", + "path": "/category3" + } + ] + - code: "400" + endpoint: /api/v1/categories + body: | + { + "status": 400, + "error": "Bad Request", + "error_details": { + "message": "Use of the category API requires a configurable channel. The project you requested uses a static configuration though." + } + } diff --git a/content/reference/public-api/document-categories/get_category.yaml b/content/reference/public-api/document-categories/get_category.yaml new file mode 100644 index 000000000..3632daff2 --- /dev/null +++ b/content/reference/public-api/document-categories/get_category.yaml @@ -0,0 +1,56 @@ +title: Get a Category with all Information +description: | + You need to activate the [Categories]({{< ref "/reference/project-config/categories" >}}) / [Routing]({{< ref "/reference/project-config/content-types#routing" >}}) feature in the Project Config in order to query categories. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/categories/:categoryId" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/categories/:categoryId +parameters: + - name: :categoryId + type: string + required: true + notes: Id of a specific categories as fetched from the /categories endpoint + - name: ?inheritMetadata + type: boolean + required: false + notes: If set to `true` will inherit (but not overwrite) metadata properties from all parents Inheritance depth is limited to 20 +responses: + - code: "200" + endpoint: /api/v1/categories/123abc + body: | + { + "id": "123abc", + "label": "Sport", + "path": "/sport", + "metadata": { + "adId": "sport-ads", + "analyticsCode": "sport-analytics" + } + } + + - code: "400" + endpoint: /api/v1/categories/123abc + body: | + { + "status": 400, + "error": "Bad Request", + "error_details": { + "message": "Use of the category API requires a configurable channel. The project you requested uses a static configuration though." + } + } + + - code: "500" + endpoint: /api/v1/categories/123abc + body: | + { + "status": 500, + "error": "Bad Request", + "error_details": { + "message": "Inheritance queries can only be made up to a depth of 20." + } + } diff --git a/content/reference/public-api/document-command-api.md b/content/reference/public-api/document-command-api.md index fb35861ab..6482ab0ea 100644 --- a/content/reference/public-api/document-command-api.md +++ b/content/reference/public-api/document-command-api.md @@ -7,306 +7,4 @@ menus: parent: Public API --- -{{< api-example -title="Execute Commands on Documents" -scopes="public-api:write" ->}} - ---query-- - -```bash -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-- -|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.

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 -```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" - }, - { - // 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" - } - ] -} -``` - ---description-- -Execute a Document Command based on its `id`. -All commands run in a single transaction. - ---response-- -204 ---- -api/v1/documents/:id/commands ---- -```js -{ - "status": 204 -} -``` ------ -400 ---- -api/v1/documents/:id/commands ---- -```js -{ - "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 ---- -api/v1/documents/:id/commands ---- -```js -{ - "status": 404, - "error": "Not Found", - "error_details": { - "name": "NotFound", - "message": "Document Not Found" - } -} -``` ------ -409 ---- -api/v1/documents/:id/commands ---- -```js -{ - "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'" - } -} -``` - -{{< /api-example >}} +{{< api-example-resource file="document_commands.yaml" >}} diff --git a/content/reference/public-api/document-lists.md b/content/reference/public-api/document-lists.md deleted file mode 100644 index 52bb5c350..000000000 --- a/content/reference/public-api/document-lists.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: Document Lists -weight: 6 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get List by Id" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/document-lists/:id?reverse=false&limit=20" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/document-lists/:id -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:id|integer|x|| -|?reverse|boolean||Pass 'reverse=false' to get the list in the same order as you see it in the editor. (the default is reverse=true for backwards compatibility reasons)| -|?fields|string||Filters which (comma separated) document properties are included in the response. Defaults to 'systemdata,metadata' also accepts 'content' (no renditions).| -|?limit|integer||A limit for how much documents to resolve for the requested list. Defaults to 100. Max. 100.| -|?ignoreComponentConditions|boolean||Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string||JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- -This endpoint resolves the referenced documents in a list.
-The response is a JSON object including list information with resolved documents. - -##### Use Cases - -- Resolve a Document List in the delivery - ---response-- -200 ---- -api/v1/document-lists/1 ---- -```js -{ - "id": 1, - "name": "List one", - "documents": [ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {}, - "test": { - "callCount": 3, - "message": "li-test called 3 times", - "events": [ - "onUpdate", - "onUpdate", - "onPreparePublish" - ] - }, - "testDependency": "li-test-dependency.onUpdate is correct" - } - } - ], - "createdAt": "2020-11-05T10:55:51.255Z", - "updatedAt": "2020-11-05T10:55:51.255Z" -} -``` - -{{< /api-example >}} - -{{< api-example - title="Get Lists" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/document-lists" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/document-lists -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|?name|string|Filters the result set and allows searching by list name.| -|?limit|integer|A limit for how much document lists to retrieve. Defaults to 10. Max. 100.| -|?offset|integer|An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- -The response is a JSON array including only document lists without resolving documents. ---response-- -200 ---- -api/v1/document-lists ---- -```js -[ - { - "id": 1, - "name": "List one", - "createdAt": "2020-11-05T10:55:51.255Z", - "updatedAt": "2020-11-05T10:55:51.255Z" - }, - { - "id": 2, - "name": "List two", - "createdAt": "2020-11-05T11:09:16.561Z", - "updatedAt": "2020-11-05T11:09:16.561Z" - }, - { - "id": 3, - "name": "List three", - "createdAt": "2020-11-05T11:09:37.213Z", - "updatedAt": "2020-11-05T11:09:37.213Z" - }, - { - "id": 4, - "name": "List four", - "createdAt": "2020-11-05T11:08:53.765Z", - "updatedAt": "2020-11-05T11:08:53.765Z" - } -] -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/document-lists/_index.md b/content/reference/public-api/document-lists/_index.md new file mode 100644 index 000000000..66f086620 --- /dev/null +++ b/content/reference/public-api/document-lists/_index.md @@ -0,0 +1,12 @@ +--- +title: Document Lists +weight: 6 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_list_by_id.yaml" >}} + +{{< api-example-resource file="get_lists.yaml" >}} diff --git a/content/reference/public-api/document-lists/get_list_by_id.yaml b/content/reference/public-api/document-lists/get_list_by_id.yaml new file mode 100644 index 000000000..b8146eb5c --- /dev/null +++ b/content/reference/public-api/document-lists/get_list_by_id.yaml @@ -0,0 +1,93 @@ +title: Get List by Id +description: | + This endpoint resolves the referenced documents in a list. + The response is a JSON object including list information with resolved documents. + +useCases: | + - Resolve a Document List in the delivery + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/document-lists/:id?reverse=false&limit=20" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/document-lists/:id +parameters: + - name: :id + type: integer + required: true + notes: "" + - name: ?reverse + type: boolean + required: false + notes: "Pass 'reverse=false' to get the list in the same order as you see it in the editor. (the default is reverse=true for backwards compatibility reasons)" + - name: ?fields + type: string + required: false + notes: "Filters which (comma separated) document properties are included in the response. Defaults to 'systemdata,metadata' also accepts 'content' (no renditions)." + - name: ?limit + type: integer + required: false + notes: "A limit for how much documents to resolve for the requested list. Defaults to 100. Max. 100." + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in "release-2024-03" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in "release-2024-03" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `dateTime: new Date()` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + +responses: + - code: "200" + endpoint: /api/v1/document-lists/1 + body: | + { + "id": 1, + "name": "List one", + "documents": [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {}, + "test": { + "callCount": 3, + "message": "li-test called 3 times", + "events": [ + "onUpdate", + "onUpdate", + "onPreparePublish" + ] + }, + "testDependency": "li-test-dependency.onUpdate is correct" + } + } + ], + "createdAt": "2020-11-05T10:55:51.255Z", + "updatedAt": "2020-11-05T10:55:51.255Z" + } diff --git a/content/reference/public-api/document-lists/get_lists.yaml b/content/reference/public-api/document-lists/get_lists.yaml new file mode 100644 index 000000000..08c069ab5 --- /dev/null +++ b/content/reference/public-api/document-lists/get_lists.yaml @@ -0,0 +1,55 @@ +title: Get Lists +description: | + The response is a JSON array including only document lists without resolving documents. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/document-lists" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/document-lists +parameters: + - name: ?name + type: string + required: false + notes: "Filters the result set and allows searching by list name" + - name: ?limit + type: integer + required: false + notes: "A limit for how much document lists to retrieve. Defaults to 10. Max. 100" + - name: ?offset + type: integer + required: false + notes: "An offset into the query. Useful when getting more than 100 results (pagination)" +responses: + - code: "200" + endpoint: /api/v1/document-lists + body: | + [ + { + "id": 1, + "name": "List one", + "createdAt": "2020-11-05T10:55:51.255Z", + "updatedAt": "2020-11-05T10:55:51.255Z" + }, + { + "id": 2, + "name": "List two", + "createdAt": "2020-11-05T11:09:16.561Z", + "updatedAt": "2020-11-05T11:09:16.561Z" + }, + { + "id": 3, + "name": "List three", + "createdAt": "2020-11-05T11:09:37.213Z", + "updatedAt": "2020-11-05T11:09:37.213Z" + }, + { + "id": 4, + "name": "List four", + "createdAt": "2020-11-05T11:08:53.765Z", + "updatedAt": "2020-11-05T11:08:53.765Z" + } + ] diff --git a/content/reference/public-api/document_commands.yaml b/content/reference/public-api/document_commands.yaml new file mode 100644 index 000000000..133f2a63b --- /dev/null +++ b/content/reference/public-api/document_commands.yaml @@ -0,0 +1,308 @@ +title: Execute Commands on Documents +description: | + Execute a Document Command based on its `id`. + All commands run in a single transaction. + +scopes: public-api:write +query: | + 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: + method: PATCH + path: /api/v1/documents/:id/commands +parameters: + - name: version + type: integer + required: false + notes: "Current document version. When set on update the version is checked." + - name: preconditions + type: array + required: false + notes: | + 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. + - name: commands + type: array + required: true + notes: | + An 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" + } + ] + } +responses: + - code: "204" + endpoint: /api/v1/documents/:id/commands + body: | + { + "status": 204 + } + - code: "400" + endpoint: /api/v1/documents/:id/commands + body: | + { + "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 + } + } + - code: "404" + endpoint: /api/v1/documents/:id/commands + body: | + { + "status": 404, + "error": "Not Found", + "error_details": { + "name": "NotFound", + "message": "Document Not Found" + } + } + - code: "409" + endpoint: /api/v1/documents/:id/commands + body: | + { + "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'" + } + } diff --git a/content/reference/public-api/drafts/_index.md b/content/reference/public-api/drafts/_index.md index 366f71766..ff177d04a 100644 --- a/content/reference/public-api/drafts/_index.md +++ b/content/reference/public-api/drafts/_index.md @@ -5,4 +5,4 @@ weight: 5 menus: reference: parent: Public API ---- \ No newline at end of file +--- diff --git a/content/reference/public-api/drafts/incoming-references.md b/content/reference/public-api/drafts/incoming-references.md index 3f1e63836..823edd30f 100644 --- a/content/reference/public-api/drafts/incoming-references.md +++ b/content/reference/public-api/drafts/incoming-references.md @@ -8,76 +8,4 @@ menus: parent: Drafts --- -{{< api-example - title="Get Incoming Draft References for a Document" - scopes="public-api:drafts:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/drafts/:documentId/incomingDocumentReferences" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/drafts/:documentId/incomingDocumentReferences -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?limit|integer||A limit for how much documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer||An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- - -This endpoint is functionally equivalent to the [Incoming Document References]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) endpoint for publications. But with this draft endpoint you will receive references from unpublished documents as well as references from the current state of documents even if these latest updates to the document are not published yet. - -##### Related - -- [Incoming Document References]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) (for publications) - ---response-- -200 ---- ---- -```js -[ - { - "id": 4, - "references": [ - { - "id": "1", - "type": "document", - "location": "include-directive", - "componentId": "doc-1euiflvoq0", - "serviceName": "editable-teaser", - "propertyName": "article", - "componentName": "teaser-include", - "directiveName": "teaser" - } - ] - }, - { - "id": 2, - "references": [ - { - "id": "1", - "type": "document", - "location": "include-directive", - "componentId": "doc-1eu6i7l880", - "serviceName": "editable-teaser", - "propertyName": "article", - "componentName": "teaser-include", - "directiveName": "teaser" - } - ] - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="incoming-references.yaml" >}} diff --git a/content/reference/public-api/drafts/incoming-references.yaml b/content/reference/public-api/drafts/incoming-references.yaml new file mode 100644 index 000000000..c7e5836f7 --- /dev/null +++ b/content/reference/public-api/drafts/incoming-references.yaml @@ -0,0 +1,65 @@ +title: Get Incoming Draft References for a Document +description: | + This endpoint is functionally equivalent to the [Incoming Document References]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) endpoint for publications. But with this draft endpoint you will receive references from unpublished documents as well as references from the current state of documents even if these latest updates to the document are not published yet. + + + ##### Related + - [Incoming Document References]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) (for publications) + +scopes: public-api:drafts:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/drafts/:documentId/incomingDocumentReferences" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/drafts/:documentId/incomingDocumentReferences +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?limit + type: integer + required: false + notes: A limit for how much documents to retrieve. Defaults to 100. Max. 100. + - name: ?offset + type: integer + required: false + notes: An offset into the query. Useful when getting more than 100 results (pagination). +responses: + - code: "200" + name: OK + body: | + [ + { + "id": 4, + "references": [ + { + "id": "1", + "type": "document", + "location": "include-directive", + "componentId": "doc-1euiflvoq0", + "serviceName": "editable-teaser", + "propertyName": "article", + "componentName": "teaser-include", + "directiveName": "teaser" + } + ] + }, + { + "id": 2, + "references": [ + { + "id": "1", + "type": "document", + "location": "include-directive", + "componentId": "doc-1eu6i7l880", + "serviceName": "editable-teaser", + "propertyName": "article", + "componentName": "teaser-include", + "directiveName": "teaser" + } + ] + } + ] diff --git a/content/reference/public-api/drafts/latest-draft-beta.md b/content/reference/public-api/drafts/latest-draft-beta.md index 80e5eaae5..c50856465 100644 --- a/content/reference/public-api/drafts/latest-draft-beta.md +++ b/content/reference/public-api/drafts/latest-draft-beta.md @@ -8,123 +8,5 @@ menus: parent: Drafts --- -{{< api-example - title="Get Latest Draft" - scopes="public-api:write, public-api:drafts:read" - beta=true ->}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/beta/documents/:documentId/latestDraft" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/beta/documents/:documentId/latestDraft -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?renditions|string||A comma-separated list of rendition handles. Example: `?renditions=web,json`| -|?ignoreComponentConditions|boolean||Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string||JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- -This endpoint returns the most recent draft version of a document. - -The response is a JSON object with 5 possible top-level properties: - -- systemdata -- metadata -- content -- references -- renditions (deprecated) - -##### Use Cases - -- Automation: Fetch draft, modify draft with an external system, update a draft via [Document Command API]({{< ref "/reference/public-api/document-command-api" >}}) -- Create a [Document Preview]({{< ref "/guides/editor/document-previews" >}}) with an external draft service -- Drafts [Delivery Build]({{< ref "/guides/editor/publish-control/delivery" >}}) (Digital Ausgabe) - - ---response-- -200 ---- ---- -```js -{ - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 603, - "contentType": "regular", - "documentType": "article", - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-02-22T16:33:42.836Z", - "design": { - "name": "living-times", - "version": "1.0.4" - } - }, - "content": [ - { - "id": "doc-1fsh4faeo0", - "component": "article-container", - "identifier": "living-times.article-container", - "position": "fixed", - "containers": { - "main": [ - { - "id": "doc-1fsh4faeo3", - "component": "paragraph", - "identifier": "living-times.paragraph", - "content": { - "text": "First paragraph published." - } - }, - { - "id": "doc-1fsh4g83l0", - "component": "paragraph", - "identifier": "living-times.paragraph", - "content": { - "text": "Second paragraph unpublished." - } - } - ] - } - } - ], - "references": [ - { - "id": "KjqXSj2P1-L0", - "type": "language-group", - "location": "metadata", - "propertyName": "language" - } - ], - "metadata": { - "language": { - "label": "German", - "locale": "de", - "groupId": "KjqXSj2P1-L0" - }, - "title": "Draft (Changed)" - }, - "renditions": [ - { - "handle": "web", - // ... - } - ] -} -``` - -{{< /api-example >}} +{{< api-example-resource file="latest-draft-beta.yaml" >}} diff --git a/content/reference/public-api/drafts/latest-draft-beta.yaml b/content/reference/public-api/drafts/latest-draft-beta.yaml new file mode 100644 index 000000000..765cb8b89 --- /dev/null +++ b/content/reference/public-api/drafts/latest-draft-beta.yaml @@ -0,0 +1,127 @@ +title: Get Latest Draft +beta: true +description: | + This endpoint returns the most recent draft version of a document. + + The response is a JSON object with 5 possible top-level properties: + + - systemdata + - metadata + - content + - references + - renditions (deprecated) + +useCases: | + - Automation: Fetch draft, modify draft with an external system, update a draft via [Document Command API]({{< ref "/reference/public-api/document-command-api" >}}) + - Create a [Document Preview]({{< ref "/guides/editor/document-previews" >}}) with an external draft service + - Drafts [Delivery Build]({{< ref "/guides/editor/publish-control/delivery" >}}) (Digital Ausgabe) + +scopes: public-api:write, public-api:drafts:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/beta/documents/:documentId/latestDraft" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/beta/documents/:documentId/latestDraft +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?renditions + type: string + required: false + notes: | + A comma-separated list of rendition handles. Example: `?renditions=web,json` + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in "release-2024-03" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in "release-2024-03" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `dateTime: new Date()` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + +responses: + - code: "200" + name: OK + body: | + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 603, + "contentType": "regular", + "documentType": "article", + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-02-22T16:33:42.836Z", + "design": { + "name": "living-times", + "version": "1.0.4" + } + }, + "content": [ + { + "id": "doc-1fsh4faeo0", + "component": "article-container", + "identifier": "living-times.article-container", + "position": "fixed", + "containers": { + "main": [ + { + "id": "doc-1fsh4faeo3", + "component": "paragraph", + "identifier": "living-times.paragraph", + "content": { + "text": "First paragraph published." + } + }, + { + "id": "doc-1fsh4g83l0", + "component": "paragraph", + "identifier": "living-times.paragraph", + "content": { + "text": "Second paragraph unpublished." + } + } + ] + } + } + ], + "references": [ + { + "id": "KjqXSj2P1-L0", + "type": "language-group", + "location": "metadata", + "propertyName": "language" + } + ], + "metadata": { + "language": { + "label": "German", + "locale": "de", + "groupId": "KjqXSj2P1-L0" + }, + "title": "Draft (Changed)" + }, + "renditions": [ + { + "handle": "web", + // ... + } + ] + } diff --git a/content/reference/public-api/get-started.md b/content/reference/public-api/get-started.md deleted file mode 100644 index 679eb269e..000000000 --- a/content/reference/public-api/get-started.md +++ /dev/null @@ -1,274 +0,0 @@ ---- -title: Get Started -weight: 1 -renderTOC: false -menus: - reference: - parent: Public API ---- - -## Authorization -To work with the Public API first go to the Project Settings page in the Livingdocs Editor and create an `AccessToken`. The token is scoped to the project so make sure you create the token in the correct project. - -Project admins can create new `AccessToken` by going to `Menu` > `Preferences` > `Project Admin`, from the project landing page. -On the sidebar, go to `Api Clients` and start the token creation flow with `Add Api Client` on the right. - -In the create token dialog, you can set the name of the token, description (optional), expiration date and permissions. You can click `Create` to generate the token with the chosen permissions. The token will be generated and you can copy it to your clipboard. - -Embed the `AccessToken` in the header of every HTTP request as shown below. - - -### Request HTTP headers - -``` -Authorization: Bearer ey1234 -``` - -### Auth Example with Curl - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "http://localhost:9090/api/v1/project" - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - -### Auth Example with Axios - -```js -const axios = require('axios') -const token = 'ey1234' -const result = await axios.get('api/v1/project', { - baseURL: 'http://localhost:9090', - headers: {Authorization: `Bearer ${token}`}, - timeout: 20000 -}) -``` - -## Errors -Common error responses you can expect when working with the public Api. - -{{< api-example - showResponseCode=true ->}} ---query-- ---endpoint-- ---parameters-- ---description-- ---response-- -401 ---- ---- -```js -{ - "status": 401, - "error": "Unauthorized", - "error_details": { - "access_token": "The access token expired." - } -} -``` -{{< /api-example >}} - -{{< api-example - showResponseCode=true ->}} ---query-- ---endpoint-- ---parameters-- ---description-- ---response-- -403 ---- ---- -```js -{ - "status": 403, - "error": "Forbidden", - "error_details": { - "access_token": "The request requires higher privileges" - } -} -``` -{{< /api-example >}} - -{{< api-example - showResponseCode=true ->}} ---query-- ---endpoint-- ---parameters-- ---description-- ---response-- -404 ---- ---- -```js -{ - "status": 404, - "error": "Not Found", - "error_details": { - "url": "/api/v1/foo" - } -} -``` -{{< /api-example >}} - -## Base URL -This is the base Url you will need to interact with our API. - -``` -https://server.livingdocs.io/ -``` - -## My First Response -For testing purposes, you can go and run the following code snippet in your Terminal. - -Don't forget to replace [your token.](https://edit.livingdocs.io/access/111/public-api) - -{{< api-example - title="Get your First Response" - responseBlurry=true ->}} - ---query-- - -```bash -curl -k -X GET https://server.livingdocs.io/api/v1/documents/latestPublications \ - -H "Authorization: Bearer your_token" -``` - ---endpoint-- ---parameters-- ---description-- ---response-- -200 ---- ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-18T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - }, - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 2, - "contentType": "article", - "documentType": "article", - "publicationId": 5, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-19T17:33:05.171Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "another title", - "description": "some other lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - } -] -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/get-started/_index.md b/content/reference/public-api/get-started/_index.md new file mode 100644 index 000000000..fe7c43135 --- /dev/null +++ b/content/reference/public-api/get-started/_index.md @@ -0,0 +1,15 @@ +--- +title: Get Started +weight: 1 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="auth_example.yaml" >}} + +{{< api-example-resource file="auth_errors.yaml" >}} + +{{< api-example-resource file="first_response.yaml" >}} + diff --git a/content/reference/public-api/get-started/auth_errors.yaml b/content/reference/public-api/get-started/auth_errors.yaml new file mode 100644 index 000000000..d7fa2bbe0 --- /dev/null +++ b/content/reference/public-api/get-started/auth_errors.yaml @@ -0,0 +1,35 @@ +title: Common Errors +description: | + Common error responses you can expect when working with the public Api. + +responses: + - code: "401" + collapsible: false + body: | + { + "status": 401, + "error": "Unauthorized", + "error_details": { + "access_token": "The access token expired." + } + } + - code: "403" + collapsible: false + body: | + { + "status": 403, + "error": "Forbidden", + "error_details": { + "access_token": "The request requires higher privileges" + } + } + - code: "404" + collapsible: false + body: | + { + "status": 404, + "error": "Not Found", + "error_details": { + "url": "/api/v1/foo" + } + } diff --git a/content/reference/public-api/get-started/auth_example.yaml b/content/reference/public-api/get-started/auth_example.yaml new file mode 100644 index 000000000..f9cbf96d6 --- /dev/null +++ b/content/reference/public-api/get-started/auth_example.yaml @@ -0,0 +1,43 @@ +title: Authorization +description: | + To work with the Public API first go to the Project Settings page in the Livingdocs Editor and create an `AccessToken`. The token is scoped to the project so make sure you create the token in the correct project. + + Project admins can create new `AccessToken` by going to `Menu` > `Preferences` > `Project Admin`, from the project landing page. + On the sidebar, go to `Api Clients` and start the token creation flow with `Add Api Client` on the right. + + In the create token dialog, you can set the name of the token, description (optional), expiration date and permissions. You can click `Create` to generate the token with the chosen permissions. The token will be generated and you can copy it to your clipboard. + + Embed the `AccessToken` in the header of every HTTP request as shown below. + + ##### Base URL + This is the base Url you will need to interact with our API. + + ``` + https://server.livingdocs.io/ + ``` + + ##### Request HTTP headers + + ``` + Authorization: Bearer ey1234 + ``` + + ##### Auth Example with Curl + + ```bash + ACCESS_TOKEN=ey1234 + curl -k -X GET "http://localhost:9090/api/v1/project" + -H "Authorization: Bearer $ACCESS_TOKEN" + ``` + + ##### Auth Example with Axios + + ```js + const axios = require('axios') + const token = 'ey1234' + const result = await axios.get('api/v1/project', { + baseURL: 'http://localhost:9090', + headers: {Authorization: `Bearer ${token}`}, + timeout: 20000 + }) + ``` diff --git a/content/reference/public-api/get-started/first_response.yaml b/content/reference/public-api/get-started/first_response.yaml new file mode 100644 index 000000000..bfe7232a4 --- /dev/null +++ b/content/reference/public-api/get-started/first_response.yaml @@ -0,0 +1,75 @@ +title: Get your First Response +description: | + For testing purposes, you can go and run the following code snippet in your Terminal. + + Don't forget to replace [your token.](https://edit.livingdocs.io/access/111/public-api) + +query: | + curl -k -X GET https://server.livingdocs.io/api/v1/documents/latestPublications \ + -H "Authorization: Bearer your_token" +responses: + - code: "200" + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-03-18T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + } + ] diff --git a/content/reference/public-api/health.md b/content/reference/public-api/health.md deleted file mode 100644 index 4663d9c83..000000000 --- a/content/reference/public-api/health.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Health -weight: 16 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Check API Status" ->}} - ---query-- - -```bash -curl -k -X GET "https://server.livingdocs.io/api/v1/health" -``` - ---endpoint-- -``` -GET api/v1/health -``` - ---parameters-- - ---description-- - -##### Use Cases - -- Health check for operations - ---response-- -200 ---- ---- -```js -{ - "status": "ok" -} -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/health/_index.md b/content/reference/public-api/health/_index.md new file mode 100644 index 000000000..892cd6fdc --- /dev/null +++ b/content/reference/public-api/health/_index.md @@ -0,0 +1,10 @@ +--- +title: Health +weight: 16 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="health_check.yaml" >}} diff --git a/content/reference/public-api/health/health_check.yaml b/content/reference/public-api/health/health_check.yaml new file mode 100644 index 000000000..58c6da4ef --- /dev/null +++ b/content/reference/public-api/health/health_check.yaml @@ -0,0 +1,15 @@ +title: Check API Status +useCases: | + - Health check for operations + +query: | + curl -k -X GET "https://server.livingdocs.io/api/v1/health" +endpoint: + method: GET + path: /api/v1/health +responses: + - code: "200" + body: | + { + "status": "ok" + } diff --git a/content/reference/public-api/imports/check_files_import_status.yaml b/content/reference/public-api/imports/check_files_import_status.yaml new file mode 100644 index 000000000..1ff959df7 --- /dev/null +++ b/content/reference/public-api/imports/check_files_import_status.yaml @@ -0,0 +1,63 @@ +title: Check Import Status for Files +description: | + You can use this endpoint to check for the status and/or result of a file import. + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/import/files/status" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/import/files/status +parameters: + - name: ?id + type: string + required: true + notes: The id that Livingdocs provided you for your prior call to `/api/v1/import/files` +responses: + - code: "200" + endpoint: /api/v1/import/files/status?id=25bzj8j + body: | + { + "finished": true, + "state": "success", + "id": "25bzj8j", + "files": [ + { + "status": "success", + "mediaId": "jjiwhsf23kdk", + "systemName": "identifier-for-your-system", + "externalId": "external-unique-id-123" + }, + { + "status": "skipped", + "reason": "already exists", + "systemName": "identifier-for-your-system", + "externalId": "external-unique-id-234" + }, + { + "status": "failed", + "reason": "Could not upload file", + "systemName": "identifier-for-your-system", + "externalId": "external-unique-id-345" + } + ] + } + - code: "200" + endpoint: /api/v1/import/files/status?id=243kdc + body: | + { + "finished": false, + "state": "started", + "id": "243kdc", + "startedAt": "2020-01-01 13:45:12" + } + - code: "200" + endpoint: /api/v1/import/files/status?id=098shjhv9 + body: | + { + "finished": true, + "state": "failed", + "id": "098shjhv9" + } diff --git a/content/reference/public-api/imports/check_video_import_status.yaml b/content/reference/public-api/imports/check_video_import_status.yaml new file mode 100644 index 000000000..3551763b9 --- /dev/null +++ b/content/reference/public-api/imports/check_video_import_status.yaml @@ -0,0 +1,82 @@ +title: Check Import Status for Videos +description: | + You can use this endpoint to check for the status and/or result of a video import. + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/import/videos/status" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/import/videos/status +parameters: + - name: ?id + type: string + required: true + notes: The id that Livingdocs provided you for your prior call to `/api/v1/import/videos` +responses: + - code: "200" + endpoint: /api/v1/import/videos/status?id=25bzj8j + body: | + { + "finished": true, + "state": "success", + "id": "25bzj8j", + "videos": [ + { + "status": "success", + "externalId": "external-unique-id-123", + "title": "my video", + "video": { + "mediaId": "jjiwhsf23kdk", + "originalUrl": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg", + "url": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "width": 100, + "height": 100, + "mimeType": "video/png", + "videoService": "imgix" + } + }, + { + "status": "skipped", + "reason": "already exists", + "externalId": "external-unique-id-234", + "title": "my second video", + "video": { + "mediaId": "jjiwhsf23wer", + "originalUrl": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "url": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "width": 100, + "height": 100, + "mimeType": "video/png", + "videoService": "imgix" + } + }, + { + "status": "failed", + "reason": "Could not upload video", + "externalId": "external-unique-id-345", + "title": "my third video" + } + ] + } + + - code: "200" + endpoint: /api/v1/import/videos/status?id=243kdc + body: | + { + "finished": false, + "state": "started", + "id": "243kdc", + "startedAt": "2020-01-01 13:45:12" + } + + - code: "200" + endpoint: /api/v1/import/videos/status?id=098shjhv9 + body: | + { + "finished": true, + "state": "failed", + "id": "098shjhv9" + } diff --git a/content/reference/public-api/imports/documents.md b/content/reference/public-api/imports/documents.md index 62a366aed..ad6398de1 100644 --- a/content/reference/public-api/imports/documents.md +++ b/content/reference/public-api/imports/documents.md @@ -7,221 +7,6 @@ menus: parent: Imports --- -{{< api-example - title="Import Documents" - scopes="public-api:write" ->}} +{{< api-example-resource file="import_documents.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/import/documents" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/document-import", - "documents": [] - } -EOF -``` - ---endpoint-- -``` -POST api/v1/import/documents -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|systemName|string|x|Identifier for the system you are importing from, e.g. an archive| -|webhook|uri||Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview.| -|context|object||An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes.| -|documents|array|x|An array of documents to import. Each entry is an object with the following keys:

**id:** a unique id (stored as externalId in Livingdocs) that identifies the document on your end, must be unique within your project.
**title:** the title that the document should get in livingdocs
**checksum:** string to identify changes, e.g. an updated_at timestamp
**contentType:** the content type that the document should get in livingdocs
**publishControl:** An object with
- `firstPublicationDate`: sets the first publication date
- `significantPublicationDate`: ({{< added-in "release-2023-07" >}}) sets a date which can be used by deliveries to display to viewers
- `visiblePublicationDateOverride`: ({{< added-in "release-2024-01" >}}) sets a date which can be used by deliveries to display to viewers
- `lastPublicationDate`: sets the most recent publication date
The `autoPublish` flag must be set for 'publishControl' to have an effect.
**publicationDate:** ({{< deprecated-in "release-2023-03" >}})
Please use `publishControl.lastPublicationDate`. Sets the most recent publication date. The `autoPublish` flag must be set for this to have an effect.
**content:** (optional) An array of livingdocs components, must conform to your channel-config otherwise throws a validation error
**design:** (optional) An object with `name` and `version`. If no design is set it takes the design of the Project Config with the latest version
**metadata:** (optional) An object of metadata, must conform to your channel-config otherwise throws a validation error
**translations:** (optional) An object of translations
**flags:** (optional) define additional import logic:
- `autoPublish`: publishes imported documents immediately
- `unpublish`: unpublishes imported documents immediately
- `onlyOverwriteUntouched`: only update documents that have no manual changes in livingdocs
- `neverOverwrite`: never update documents through the import API| - -#### Example Request -```js -{ - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/document-import", - "context": { - "myIdentifier": "some-identifier-sent-to-the-webhook" - }, - "documents": [ - { - "id": "123abc", - "title": "test import", - "contentType": "article", - "checksum": "xyz456", - "publishControl": { - "firstPublicationDate": "1999-03-18T17:27:00.107Z", - "significantPublicationDate": "1999-03-19T17:27:00.107Z", - "lastPublicationDate": "1999-03-20T17:27:00.107Z", - }, - "content": [ - { - "identifier": "header", - "content": { - "catchline": "imported catchline", - "title": "imported title", - "author": "imported author" - } - } - ], - "design": { - "name": "living-times", - "version": "1.0.1" - }, - "metadata": { - "description": "foo" - }, - "translations": [ - { - "locale": "fr", - "metadata": { - "description": "foo FR" - } - } - ], - "flags": { - "autoPublish": true - } - } - ] -} -``` - ---description-- -The document import does both create and update documents. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update documents). The document import in Livingdocs is asynchronous. You post a batch of documents that you want to import and get back an id with which you can query later to get your result. - -##### Use Cases - -- [Initial Import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) -- Feed Imports e.g. [DPA Import]({{< ref "/guides/integrations/dpa-import" >}}) - ---response-- -200 ---- -api/v1/import/documents ---- -```js -{ - "id": "25bzj8j" -} -``` - -{{< /api-example >}} - -{{< api-example - title="Check Import Status for Documents" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/import/documents/status" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/import/documents/status -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|?id|string|x|The id that Livingdocs provided you for your prior call to "/import/documents"| - ---description-- -You can use this endpoint to check for the status and/or result of a document import. - ---response-- -200 ---- -api/v1/import/documents/status?id=25bzj8j ---- -```js -{ - "finished": true, - "state": "success", - "id": "25bzj8j", - "logs": [ - { - "state": "imported", - "system_name": "external-system-name", - "external_id": "8Sv9Nu0d", - "document_id": 1, - "checksum": "123abc", - "project_id": 3, - "channel_id": 2, - "revision_id": 4602, - "version": 1, - "id": 1 - }, - { - "state": "published", - "created_at": "2024-12-03T23:38:29.789Z", - "updated_at": "2024-12-03T23:38:29.789Z", - "system_name": "external-system-name", - "external_id": "9av23oaf", - "document_id": 1148, - "checksum": "10", - "project_id": 3, - "channel_id": 2, - "revision_id": 4603, - "version": 1 - "id": 1, - }, - { - "state": "failed", - "reason": "Invalid metadata", - "external_id": "external-unique-id-345", - "title": "my second document" - } - ] -} -``` ------ -200 ---- -api/v1/import/documents/status?id=243kdc ---- -```js -{ - "finished": false, - "state": "started", - "id": "243kdc", - "startedAt": "2020-01-01 13:45:12" -} -``` ------ -200 ---- -api/v1/import/documents/status?id=098shjhv9 ---- -```js -{ - "finished": true, - "state": "failed", - "id": "098shjhv9" -} -``` ------ -200 ---- -api/v1/import/documents/status?id=098shjhv9 ---- -```js -{ - "finished": false, - "state": "lost", - "id": "no import job found for id \"098shjhv9\"" -} -``` - -{{< /api-example >}} +{{< api-example-resource file="import_documents_check_status.yaml" >}} diff --git a/content/reference/public-api/imports/files.md b/content/reference/public-api/imports/files.md index 4097acc8f..e890feb94 100644 --- a/content/reference/public-api/imports/files.md +++ b/content/reference/public-api/imports/files.md @@ -7,179 +7,6 @@ menus: parent: Imports --- -{{< api-example - title="Import Files" - scopes="public-api:write" ->}} +{{< api-example-resource file="import_files.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/import/files" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/file-import", - "files": [ - { - "url": "https://placekitten.com/800/600", - "id": "123abc", - "fileName": "cat", - "metadata": { - "caption": "foo" - } - } - ] - } -EOF -``` - ---endpoint-- -``` -POST api/v1/import/files -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|systemName|string|x|Identifier for the system you are importing from, e.g. an archive.| -|webhook|uri||Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview.| -|context|object||An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes.| -|files|array|x|An array of files to import. Each entry is an object with the following keys, all of which are required:

**url:** a URL to a file
**id:** a unique id (stored as externalId in Livingdocs) that identifies the file on your end, must be unique within your project
**fileName:** the title that the file should get in livingdocs
**metadata:** An object of metadata according to your project config
**mediaType** the handle of one of the mediaTypes from your project configuration| - -#### Example Request -```js -{ - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/file-import", - "context": { - "myIdentifier": "some-identifier-sent-to-the-webhook" - }, - "files": [ - { - "url": "https://placekitten.com/800/600", - "id": "123abc", - "fileName": "cat", - "metadata": { - "caption": "foo" - } - } - ] -} -``` - ---description-- - -The file import does both create and update files. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update files). The file import in Livingdocs is asynchronous. You post a batch of files that you want to import and get back an id with which you can query later to get your result. - -##### Use Cases - -- [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) - When doing an initial import one usually first imports all files and then imports documents referencing the files. - -##### Related - -- [Document Import API]({{< ref "/reference/public-api/imports/documents" >}}) -- [Import Media Library Entries]({{< ref "/reference/public-api/imports/media-library-entries" >}}) - ---response-- -200 ---- -api/v1/import/files ---- -```js -{ - "id": "25bzj8j" -} -``` - -{{< /api-example >}} - -{{< api-example - title="Check Import Status for Files" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/import/files/status" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/import/files/status -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|?id|string|x|The id that Livingdocs provided you for your prior call to "/import/files"| - ---description-- -You can use this endpoint to check for the status and/or result of a file import. - ---response-- -200 ---- -api/v1/import/files/status?id=25bzj8j ---- - -```js -{ - "finished": true, - "state": "success", - "id": "25bzj8j", - "files": [ - { - "status": "success", - "mediaId": "jjiwhsf23kdk", - "systemName": "identifier-for-your-system", - "externalId": "external-unique-id-123" - }, - { - "status": "skipped", - "reason": "already exists", - "systemName": "identifier-for-your-system", - "externalId": "external-unique-id-234" - }, - { - "status": "failed", - "reason": "Could not upload file", - "systemName": "identifier-for-your-system", - "externalId": "external-unique-id-345" - } - ] -} -``` ------ -200 ---- -api/v1/import/files/status?id=243kdc ---- -```js -{ - "finished": false, - "state": "started", - "id": "243kdc", - "startedAt": "2020-01-01 13:45:12" -} -``` ------ -200 ---- -api/v1/import/files/status?id=098shjhv9 ---- -```js -{ - "finished": true, - "state": "failed", - "id": "098shjhv9" -} -``` - -{{< /api-example >}} +{{< api-example-resource file="check_files_import_status.yaml" >}} diff --git a/content/reference/public-api/imports/images.md b/content/reference/public-api/imports/images.md index dd4a35904..e11966bff 100644 --- a/content/reference/public-api/imports/images.md +++ b/content/reference/public-api/imports/images.md @@ -7,198 +7,6 @@ menus: parent: Imports --- -{{< api-example - title="Import Images" - scopes="public-api:write" ->}} +{{< api-example-resource file="import_images.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/import/images" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/image-import", - "images": [ - { - "url": "https://placekitten.com/800/600", - "id": "123abc", - "fileName": "cat", - "metadata": { - "caption": "foo" - } - } - ] - } -EOF -``` - ---endpoint-- -``` -POST api/v1/import/images -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|systemName|string|x|Identifier for the system you are importing from, e.g. an archive.| -|webhook|uri||Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview.| -|context|object||An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes.| -|images|array|x|An array of images to import. Each entry is an object with the following keys, all of which are required:

**url:** a URL to an image file, no data urls allowed, allowed types: png, jpg, gif, svg
**id:** a unique id (stored as externalId in Livingdocs) that identifies the image on your end, must be unique within your project
**fileName:** the title that the image should get in livingdocs
**metadata:** An object of metadata according to your project config
**mediaType** the handle of one of the mediaTypes from your project configuration| - -#### Example Request -```js -{ - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/image-import", - "context": { - "myIdentifier": "some-identifier-sent-to-the-webhook" - }, - "images": [ - { - "url": "https://placekitten.com/800/600", - "id": "123abc", - "fileName": "cat", - "metadata": { - "caption": "foo" - } - } - ] -} -``` - ---description-- - -The image import creates image entries in the Media Library and upload the image asset to the configured blob storage. The image import in Livingdocs is asynchronous. You post a batch of images that you want to import and get back a jobId that you can use to retrieve the import job state. - -You can patch existing media library entries with the [patch endpoint]({{< ref "/reference/public-api/media-library" >}}). - -##### Use Cases - -- [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) - When doing an initial import one usually first imports all images and then imports documents referencing the images. - -##### Related - -- [Document Import API]({{< ref "/reference/public-api/imports/documents" >}}) -- [Import Media Library Entries]({{< ref "/reference/public-api/imports/media-library-entries" >}}) - ---response-- -200 ---- -api/v1/import/images ---- -```js -{ - "id": "25bzj8j" -} -``` - - -{{< /api-example >}} - -{{< api-example - title="Check Import Status for Images" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/import/images/status" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/import/images/status -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|?id|string|x|The id that Livingdocs provided you for your prior call to "/import/images"| - ---description-- -You can use this endpoint to check for the status and/or result of an image import. - ---response-- -200 ---- -api/v1/import/images/status?id=25bzj8j ---- -```js -{ - "finished": true, - "state": "success", - "id": "25bzj8j", - "images": [ - { - "status": "success", - "externalId": "external-unique-id-123", - "title": "my image", - "image": { - "mediaId": "jjiwhsf23kdk", - "originalUrl": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg", - "url": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "width": 100, - "height": 100, - "mimeType": "image/png", - "imageService": "imgix" - } - }, - { - "status": "skipped", - "reason": "already exists", - "externalId": "external-unique-id-234", - "title": "my second image", - "image": { - "mediaId": "jjiwhsf23wer", - "originalUrl": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "url": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "width": 100, - "height": 100, - "mimeType": "image/png", - "imageService": "imgix" - } - }, - { - "status": "failed", - "reason": "Could not upload image", - "externalId": "external-unique-id-345", - "title": "my third image" - } - ] -} -``` ------ -200 ---- -api/v1/import/images/status?id=243kdc ---- -```js -{ - "finished": false, - "state": "started", - "id": "243kdc", - "startedAt": "2020-01-01 13:45:12" -} -``` ------ -200 ---- -api/v1/import/images/status?id=098shjhv9 ---- -```js -{ - "finished": true, - "state": "failed", - "id": "098shjhv9" -} -``` - -{{< /api-example >}} +{{< api-example-resource file="import_images_import_status.yaml" >}} diff --git a/content/reference/public-api/imports/import_documents.yaml b/content/reference/public-api/imports/import_documents.yaml new file mode 100644 index 000000000..48ff2318d --- /dev/null +++ b/content/reference/public-api/imports/import_documents.yaml @@ -0,0 +1,133 @@ +title: Import Documents +description: | + The document import does both create and update documents. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update documents). The document import in Livingdocs is asynchronous. You post a batch of documents that you want to import and get back an id with which you can query later to get your result. + +useCases: | + - [Initial Import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) + - Feed Imports e.g. [DPA Import]({{< ref "/guides/integrations/dpa-import" >}}) + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/import/documents" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/document-import", + "documents": [] + } + EOF +endpoint: + method: POST + path: /api/v1/import/documents + +parameters: + - name: systemName + type: string + required: true + notes: "Identifier for the system you are importing from, e.g. an archive" + - name: webhook + type: uri + required: false + notes: "Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview." + - name: context + type: object + required: false + notes: "An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes." + - name: documents + type: array + required: true + notes: | + An array of documents to import. Each entry is an object with the following keys: + + **id:** a unique id (stored as externalId in Livingdocs) that identifies the document on your end, must be unique within your project. + + **title:** the title that the document should get in livingdocs + + **checksum:** string to identify changes, e.g. an updated_at timestamp + + **contentType:** the content type that the document should get in livingdocs + + **publishControl:** An object with + - `firstPublicationDate`: sets the first publication date + - `significantPublicationDate`: ({{< added-in "release-2023-07" >}}) sets a date which can be used by deliveries to display to viewers + - `visiblePublicationDateOverride`: ({{< added-in "release-2024-01" >}}) sets a date which can be used by deliveries to display to viewers + - `lastPublicationDate`: sets the most recent publication date + The `autoPublish` flag must be set for 'publishControl' to have an effect. + + **publicationDate:** ({{< deprecated-in "release-2023-03" >}}) + Please use `publishControl.lastPublicationDate`. Sets the most recent publication date. The `autoPublish` flag must be set for this to have an effect. + + **content:** (optional) An array of livingdocs components, must conform to your channel-config otherwise throws a validation error + + **design:** (optional) An object with `name` and `version`. If no design is set it takes the design of the Project Config with the latest version + + **metadata:** (optional) An object of metadata, must conform to your channel-config otherwise throws a validation error + + **translations:** (optional) An object of translations + + **flags:** (optional) define additional import logic: + - `autoPublish`: publishes imported documents immediately + - `unpublish`: unpublishes imported documents immediately + - `onlyOverwriteUntouched`: only update documents that have no manual changes in livingdocs + - `neverOverwrite`: never update documents through the import API + +example_request: | + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/document-import", + "context": { + "myIdentifier": "some-identifier-sent-to-the-webhook" + }, + "documents": [ + { + "id": "123abc", + "title": "test import", + "contentType": "article", + "checksum": "xyz456", + "publishControl": { + "firstPublicationDate": "1999-03-18T17:27:00.107Z", + "significantPublicationDate": "1999-03-19T17:27:00.107Z", + "lastPublicationDate": "1999-03-20T17:27:00.107Z", + }, + "content": [ + { + "identifier": "header", + "content": { + "catchline": "imported catchline", + "title": "imported title", + "author": "imported author" + } + } + ], + "design": { + "name": "living-times", + "version": "1.0.1" + }, + "metadata": { + "description": "foo" + }, + "translations": [ + { + "locale": "fr", + "metadata": { + "description": "foo FR" + } + } + ], + "flags": { + "autoPublish": true + } + } + ] + } + +responses: + - code: "200" + endpoint: /api/v1/import/documents + body: | + { + "id": "25bzj8j" + } diff --git a/content/reference/public-api/imports/import_documents_check_status.yaml b/content/reference/public-api/imports/import_documents_check_status.yaml new file mode 100644 index 000000000..f5d152dd0 --- /dev/null +++ b/content/reference/public-api/imports/import_documents_check_status.yaml @@ -0,0 +1,87 @@ +title: Check Import Status for Documents +description: | + This endpoint allows you to check the status of a previously initiated document import. The result will indicate whether the import has finished and its state. +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/import/documents/status" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/import/documents/status +parameters: + - name: ?id + type: string + required: true + notes: The id that Livingdocs provided you for your prior call to `/api/v1/import/documents` +responses: + - code: "200" + endpoint: /api/v1/import/documents/status?id=25bzj8j + body: | + { + "finished": true, + "state": "success", + "id": "25bzj8j", + "logs": [ + { + "state": "imported", + "system_name": "external-system-name", + "external_id": "8Sv9Nu0d", + "document_id": 1, + "checksum": "123abc", + "project_id": 3, + "channel_id": 2, + "revision_id": 4602, + "version": 1, + "id": 1 + }, + { + "state": "published", + "created_at": "2024-12-03T23:38:29.789Z", + "updated_at": "2024-12-03T23:38:29.789Z", + "system_name": "external-system-name", + "external_id": "9av23oaf", + "document_id": 1148, + "checksum": "10", + "project_id": 3, + "channel_id": 2, + "revision_id": 4603, + "version": 1 + "id": 1, + }, + { + "state": "failed", + "reason": "Invalid metadata", + "external_id": "external-unique-id-345", + "title": "my second document" + } + ] + } + - code: "200" + name: OK + endpoint: /api/v1/import/documents/status?id=243kdc + body: | + { + "finished": false, + "state": "started", + "id": "243kdc", + "startedAt": "2020-01-01 13:45:12" + } + - code: "200" + name: OK + endpoint: /api/v1/import/documents/status?id=098shjhv9 + body: | + { + "finished": true, + "state": "failed", + "id": "098shjhv9" + } + - code: "200" + name: OK + endpoint: /api/v1/import/documents/status?id=098shjhv9 + body: | + { + "finished": false, + "state": "lost", + "id": "no import job found for id \"098shjhv9\"" + } diff --git a/content/reference/public-api/imports/import_files.yaml b/content/reference/public-api/imports/import_files.yaml new file mode 100644 index 000000000..4fcce9ad5 --- /dev/null +++ b/content/reference/public-api/imports/import_files.yaml @@ -0,0 +1,90 @@ +title: Import Files +description: | + The file import does both create and update files. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update files). The file import in Livingdocs is asynchronous. You post a batch of files that you want to import and get back an id with which you can query later to get your result. + + #### Related + + - [Document Import API]({{< ref "/reference/public-api/imports/documents" >}}) + - [Import Media Library Entries]({{< ref "/reference/public-api/imports/media-library-entries" >}}) + +useCases: | + - [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) - When doing an initial import one usually first imports all files and then imports documents referencing the files. + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/import/files" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/file-import", + "files": [ + { + "url": "https://placekitten.com/800/600", + "id": "123abc", + "fileName": "cat", + "metadata": { + "caption": "foo" + } + } + ] + } + EOF +endpoint: + method: POST + path: /api/v1/import/files + + +example_request: | + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/file-import", + "context": { + "myIdentifier": "some-identifier-sent-to-the-webhook" + }, + "files": [ + { + "url": "https://placekitten.com/800/600", + "id": "123abc", + "fileName": "cat", + "metadata": { + "caption": "foo" + } + } + ] + } + + +parameters: + - name: systemName + type: string + required: true + notes: "Identifier for the system you are importing from, e.g. an archive." + - name: webhook + type: uri + required: false + notes: "Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview." + - name: context + type: object + required: false + notes: "An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes." + - name: files + type: array + required: true + notes: | + An array of files to import. Each entry is an object with the following keys, all of which are required: + - **url:** a URL to a file + - **id:** a unique id (stored as externalId in Livingdocs) that identifies the file on your end, must be unique within your project + - **fileName:** the title that the file should get in livingdocs + - **metadata:** An object of metadata according to your project config + - **mediaType**: The handle of one of the mediaTypes from your project configuration +responses: + - code: "200" + name: OK + endpoint: /api/v1/import/files + body: | + { + "id": "25bzj8j" + } diff --git a/content/reference/public-api/imports/import_images.yaml b/content/reference/public-api/imports/import_images.yaml new file mode 100644 index 000000000..79f5d10d7 --- /dev/null +++ b/content/reference/public-api/imports/import_images.yaml @@ -0,0 +1,84 @@ +title: Import Images +description: | + The image import creates image entries in the Media Library and upload the image asset to the configured blob storage. The image import in Livingdocs is asynchronous. You post a batch of images that you want to import and get back a jobId that you can use to retrieve the import job state. + + You can patch existing media library entries with the [patch endpoint]({{< ref "/reference/public-api/media-library" >}}). + +useCases: | + - [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) - When doing an initial import one usually first imports all images and then imports documents referencing the images. + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/import/images" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/image-import", + "images": [ + { + "url": "https://placekitten.com/800/600", + "id": "123abc", + "fileName": "cat", + "metadata": { + "caption": "foo" + } + } + ] + } + EOF +endpoint: + method: POST + path: /api/v1/import/images +parameters: + - name: systemName + type: string + required: true + notes: "Identifier for the system you are importing from, e.g. an archive" + - name: webhook + type: uri + required: false + notes: "Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview." + - name: context + type: object + required: false + notes: "An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes." + - name: images + type: array + required: true + notes: | + An array of images to import. Each entry is an object with the following keys, all of which are required: + - **url:** a URL to an image file, no data urls allowed, allowed types: png, jpg, gif, svg
+ - **id:** a unique id (stored as externalId in Livingdocs) that identifies the image on your end, must be unique within your project
+ - **fileName:** the title that the image should get in livingdocs
+ - **metadata:** An object of metadata according to your project config
+ - **mediaType:** The handle of one of the mediaTypes from your project configuration + +example_request: | + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/image-import", + "context": { + "myIdentifier": "some-identifier-sent-to-the-webhook" + }, + "images": [ + { + "url": "https://placekitten.com/800/600", + "id": "123abc", + "fileName": "cat", + "metadata": { + "caption": "foo" + } + } + ] + } + +responses: + - code: "200" + endpoint: /api/v1/import/images + body: | + { + "id": "25bzj8j" + } diff --git a/content/reference/public-api/imports/import_images_import_status.yaml b/content/reference/public-api/imports/import_images_import_status.yaml new file mode 100644 index 000000000..062b092d9 --- /dev/null +++ b/content/reference/public-api/imports/import_images_import_status.yaml @@ -0,0 +1,85 @@ +title: Check Import Status for Images +description: | + API endpoints for importing and checking status of image imports. + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/import/images/status" \ + -H "Authorization: Bearer $ACCESS_TOKEN" + +endpoint: + method: GET + path: /api/v1/import/images/status + +parameters: + - name: id + type: string + required: true + notes: "The id that Livingdocs provided you for your prior call to '/import/images'" + +responses: + - code: "200" + endpoint: /api/v1/import/images/status?id=25bzj8j + body: | + { + "finished": true, + "state": "success", + "id": "25bzj8j", + "images": [ + { + "status": "success", + "externalId": "external-unique-id-123", + "title": "my image", + "image": { + "mediaId": "jjiwhsf23kdk", + "originalUrl": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg", + "url": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "width": 100, + "height": 100, + "mimeType": "image/png", + "imageService": "imgix" + } + }, + { + "status": "skipped", + "reason": "already exists", + "externalId": "external-unique-id-234", + "title": "my second image", + "image": { + "mediaId": "jjiwhsf23wer", + "originalUrl": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "url": "https://livingdocs-images.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", + "width": 100, + "height": 100, + "mimeType": "image/png", + "imageService": "imgix" + } + }, + { + "status": "failed", + "reason": "Could not upload image", + "externalId": "external-unique-id-345", + "title": "my third image" + } + ] + } + + - code: "200" + endpoint: /api/v1/import/images/status?id=243kdc + body: | + { + "finished": false, + "state": "started", + "id": "243kdc", + "startedAt": "2020-01-01 13:45:12" + } + + - code: "200" + endpoint: /api/v1/import/images/status?id=098shjhv9 + body: | + { + "finished": true, + "state": "failed", + "id": "098shjhv9" + } diff --git a/content/reference/public-api/imports/import_videos.yaml b/content/reference/public-api/imports/import_videos.yaml new file mode 100644 index 000000000..9a1ac36ea --- /dev/null +++ b/content/reference/public-api/imports/import_videos.yaml @@ -0,0 +1,85 @@ +title: Import Videos +description: | + The video import does both create and update videos. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update videos). The video import in Livingdocs is asynchronous. You post a batch of videos that you want to import and get back an id with which you can query later to get your result. + +useCases: | + - [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/import/videos" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/video-import", + "videos": [ + { + "url": "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4", + "id": "123abc", + "fileName": "sample", + "metadata": { + "title": "sample video" + "credit": "LC" + } + } + ] + } + EOF +endpoint: + method: POST + path: /api/v1/import/videos + +example_request: | + { + "systemName": "identifier-for-your-system", + "webhook": "https://my-domain.com/webhooks/video-import", + "context": { + "myIdentifier": "some-identifier-sent-to-the-webhook" + }, + "videos": [ + { + "url": "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4", + "id": "123abc", + "fileName": "foo", + "metadata": { + "title": "sample video", + "credit": "LC" + } + } + ] + } + + +parameters: + - name: systemName + type: string + required: true + notes: "Identifier for the system you are importing from, e.g. an archive" + - name: webhook + type: uri + required: false + notes: "Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview." + - name: context + type: object + required: false + notes: "An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes." + - name: videos + type: array + required: true + notes: | + An array of videos to import. Each entry is an object with the following keys, all of which are required: + - **url:** a URL to a video file, must reference a video file with mimetype `video/*`. + - **id:** a unique id (stored as externalId in Livingdocs) that identifies the video on your end, must be unique within your project + - **fileName:** the title that the video should get in livingdocs + - **metadata:** An object of metadata according to your project config +responses: + - code: "200" + name: OK + endpoint: /api/v1/import/videos + body: | + { + "id": "25bzj8j" + } diff --git a/content/reference/public-api/imports/media-library-entries.md b/content/reference/public-api/imports/media-library-entries.md index 9dfbbca8c..a5e8431f5 100644 --- a/content/reference/public-api/imports/media-library-entries.md +++ b/content/reference/public-api/imports/media-library-entries.md @@ -7,238 +7,4 @@ menus: parent: Imports --- -{{< api-example - title="Import Media Library Entries" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/import/mediaLibrary" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "mediaLibraryEntries": [] - } -EOF -``` - ---endpoint-- -``` -POST api/v1/import/mediaLibrary -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|mediaLibraryEntries|array|x|An array of documents to import. Each entry is an object.| -|mediaLibraryEntries.id|string||Custom id (Allowed characters: a-z, A-Z, 0-9, and -). If omitted a random id will be generated.| -|mediaLibraryEntries.systemName|string||A string identifiyng the external system where the asset is imported from. It is recommended that you always set this value and it is required if you provide an `externalId`.| -|mediaLibraryEntries.externalId|string||Must be unique in combination with `systemName`.| -|mediaLibraryEntries.mediaType|string|x|`image`, `video`, `file`| -|mediaLibraryEntries.asset|object|x|| -|mediaLibraryEntries.metadata|object||| -|mediaLibraryEntries.translations|object|| - -#### Example Request -```js -{ - "mediaLibraryEntries": [ - { - "id": "custom-1", - "systemName": "externalSystem", - "externalId": "6hedie82", - "mediaType": "image", - "asset": { - "key": "2022/08/25/d6068c02-ca85-421d-948d-ee0e2c15f372.jpeg", - "url": "https://livingdocs-images-development.s3.amazonaws.com/2022/08/25/d6068c02-ca85-421d-948d-ee0e2c15f372.jpeg", - "size": 34910, - "width": 640, - "height": 427, - "filename": "super-mario.jpeg", - "mimeType": "image/jpeg" - }, - "metadata": { - "title": "An image title" - }, - "translations": [ - { - "locale": "fr", - "metadata": { - "title": "Un titre d'image" - }, - "asset": { - "key": "2022/08/25/another-asset.jpeg", - "url": "https://livingdocs-images-development.s3.amazonaws.com/2022/08/25/another-asset.jpeg", - "size": 34910, - "width": 640, - "height": 427, - "filename": "super-mario-modified.jpeg", - "mimeType": "image/jpeg" - } - } - ] - }, - { - "id": "custom-2", - "systemName": "externalSystem", - "externalId": "ahedie8x", - "mediaType": "file", - "asset": { - "key": "2022/09/30/a1cb173d-e85f-498b-996e-5ce46058e9b9.pdf", - "url": "https://livingdocs-files-development.s3.amazonaws.com/2022/09/30/a1cb173d-e85f-498b-996e-5ce46058e9b9.pdf", - "size": 3028, - "filename": "a-simple-pdf.pdf", - "mimeType": "application/pdf" - }, - "metadata": { - "title": "A simple PDF" - }, - "translations": [ - { - "locale": "fr", - "metadata": { - "title": "Un simple PDF" - }, - "asset": { - "key": "2022/09/30/another-asset.pdf", - "url": "https://livingdocs-files-development.s3.amazonaws.com/2022/09/30/another-asset.pdf", - "size": 3028, - "filename": "a-simple-pdf-fr.pdf", - "mimeType": "application/pdf" - }, - } - ] - }, - { - "id": "custom-3", - "systemName": "externalSystem", - "externalId": "srfhediess", - "mediaType": "video", - "asset": { - "key": "2022/09/30/2804fc3d-098d-4f8f-b25c-c6c15583d672.mp4", - "url": "https://livingdocs-videos-development.s3.amazonaws.com/2022/09/30/2804fc3d-098d-4f8f-b25c-c6c15583d672.mp4", - "size": 8633462, - "width": 1280, - "height": 720, - "duration": 35.241667, - "filename": "fire.mp4", - "mimeType": "video/mp4" - }, - "metadata": { - "title": "This is a fire" - }, - "translations": [ - { - "locale": "fr", - "metadata": { - "title": "C'est un feu" - }, - "asset": { - "key": "2022/09/30/another-asset.mp4", - "url": "https://livingdocs-videos-development.s3.amazonaws.com/2022/09/30/another-asset.mp4", - "size": 8633462, - "width": 1280, - "height": 720, - "duration": 35.241667, - "filename": "fire-fr.mp4", - "mimeType": "video/mp4" - }, - } - ] - } - ] -} -``` - ---description-- -When you can upload images, videos or files to the configured Media Library storage (e.g. AWS S3) yourself it is possible to create Media Library Entries through the API. - -This has the advantage that the entries will be included in the response directly in contrast e.g. to the `api/v1/import/images` endpoint where you only get a `jobId`. - -You can also provide a custom id to entries which helps with importing documents where images in the document should be referenced with the correct `mediaId` maybe even before creating the Media Library Entries themselves. - -##### Use Cases - -- Initial import from an external system -- Self managing asset upload (images, videos, files) and creating your own Media Library Entry (easier for imports to connect Media Library Entries with its documents) - -##### Related - -- [Import Images]({{< ref "/reference/public-api/imports/images" >}}) -- [Import Videos]({{< ref "/reference/public-api/imports/videos" >}}) - - ---response-- -200 ---- -api/v1/import/mediaLibrary ---- -```js -{ - "mediaLibraryEntries": [ - { - "ok": true, - "status": 200, - "id": "custom-1", - "record": {} - } - ] -} -``` ------ -200 ---- -api/v1/import/mediaLibrary (error cases for individual entries) ---- -```js -{ - "mediaLibraryEntries": [ - { - "ok": false, - "correlation": "id: custom-1", - "status": 409, - "error": "UniqueIdViolation", - "error_details": { - "message": "id is not unique: 'custom-1'" - } - }, - { - "ok": false, - "correlation": "id: custom-2", - "status": 409, - "error": "UniqueIdViolation", - "error_details": { - "message": "externalId is not unique: 'external-1'" - } - }, - { - "ok": false, - "correlation": "id: custom-3", - "status": 400, - "error": "ValidationError", - "error_details": { - "message": "An asset with an externalId also requires a systemName" - } - }, - { - "ok": false, - "correlation": "id: custom-4", - "status": 400, - "error": "ValidationError", - "error_details": { - "message": 'Metadata validation failed.', - "errors": [{ - "metadataProperty": "title", - "message": "The value of '/title' must be string" - }] - } - } - ] -} -``` - -{{< /api-example >}} +{{< api-example-resource file="media-library-entries.yaml" >}} diff --git a/content/reference/public-api/imports/media-library-entries.yaml b/content/reference/public-api/imports/media-library-entries.yaml new file mode 100644 index 000000000..64554ee09 --- /dev/null +++ b/content/reference/public-api/imports/media-library-entries.yaml @@ -0,0 +1,229 @@ +title: Import Media Library Entries +description: | + When you can upload images, videos or files to the configured Media Library storage (e.g. AWS S3) yourself it is possible to create Media Library Entries through the API. + + This has the advantage that the entries will be included in the response directly in contrast e.g. to the `/api/v1/import/images` endpoint where you only get a `jobId`. + + You can also provide a custom id to entries which helps with importing documents where images in the document should be referenced with the correct `mediaId` maybe even before creating the Media Library Entries themselves. + +useCases: | + - Initial import from an external system + - Self managing asset upload (images, videos, files) and creating your own Media Library Entry (easier for imports to connect Media Library Entries with its documents) + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/import/mediaLibrary" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "mediaLibraryEntries": [] + } + EOF +endpoint: + method: POST + path: /api/v1/import/mediaLibrary +parameters: + - name: mediaLibraryEntries + type: array + required: true + notes: "An array of documents to import. Each entry is an object." + - name: mediaLibraryEntries.id + type: string + required: false + notes: "Custom id (Allowed characters: a-z, A-Z, 0-9, and -). If omitted a random id will be generated." + - name: mediaLibraryEntries.systemName + type: string + required: false + notes: "A string identifiyng the external system where the asset is imported from. It is recommended that you always set this value and it is required if you provide an `externalId`." + - name: mediaLibraryEntries.externalId + type: string + required: false + notes: "Must be unique in combination with `systemName`." + - name: mediaLibraryEntries.mediaType + type: string + required: true + notes: "`image`, `video`, `file`" + - name: mediaLibraryEntries.asset + type: object + required: true + notes: "" + - name: mediaLibraryEntries.metadata + type: object + required: false + notes: "" + - name: mediaLibraryEntries.translations + type: object + required: false + notes: "" + +example_request: | + { + "mediaLibraryEntries": [ + { + "id": "custom-1", + "systemName": "externalSystem", + "externalId": "6hedie82", + "mediaType": "image", + "asset": { + "key": "2022/08/25/d6068c02-ca85-421d-948d-ee0e2c15f372.jpeg", + "url": "https://livingdocs-images-development.s3.amazonaws.com/2022/08/25/d6068c02-ca85-421d-948d-ee0e2c15f372.jpeg", + "size": 34910, + "width": 640, + "height": 427, + "filename": "super-mario.jpeg", + "mimeType": "image/jpeg" + }, + "metadata": { + "title": "An image title" + }, + "translations": [ + { + "locale": "fr", + "metadata": { + "title": "Un titre d'image" + }, + "asset": { + "key": "2022/08/25/another-asset.jpeg", + "url": "https://livingdocs-images-development.s3.amazonaws.com/2022/08/25/another-asset.jpeg", + "size": 34910, + "width": 640, + "height": 427, + "filename": "super-mario-modified.jpeg", + "mimeType": "image/jpeg" + } + } + ] + }, + { + "id": "custom-2", + "systemName": "externalSystem", + "externalId": "ahedie8x", + "mediaType": "file", + "asset": { + "key": "2022/09/30/a1cb173d-e85f-498b-996e-5ce46058e9b9.pdf", + "url": "https://livingdocs-files-development.s3.amazonaws.com/2022/09/30/a1cb173d-e85f-498b-996e-5ce46058e9b9.pdf", + "size": 3028, + "filename": "a-simple-pdf.pdf", + "mimeType": "application/pdf" + }, + "metadata": { + "title": "A simple PDF" + }, + "translations": [ + { + "locale": "fr", + "metadata": { + "title": "Un simple PDF" + }, + "asset": { + "key": "2022/09/30/another-asset.pdf", + "url": "https://livingdocs-files-development.s3.amazonaws.com/2022/09/30/another-asset.pdf", + "size": 3028, + "filename": "a-simple-pdf-fr.pdf", + "mimeType": "application/pdf" + }, + } + ] + }, + { + "id": "custom-3", + "systemName": "externalSystem", + "externalId": "srfhediess", + "mediaType": "video", + "asset": { + "key": "2022/09/30/2804fc3d-098d-4f8f-b25c-c6c15583d672.mp4", + "url": "https://livingdocs-videos-development.s3.amazonaws.com/2022/09/30/2804fc3d-098d-4f8f-b25c-c6c15583d672.mp4", + "size": 8633462, + "width": 1280, + "height": 720, + "duration": 35.241667, + "filename": "fire.mp4", + "mimeType": "video/mp4" + }, + "metadata": { + "title": "This is a fire" + }, + "translations": [ + { + "locale": "fr", + "metadata": { + "title": "C'est un feu" + }, + "asset": { + "key": "2022/09/30/another-asset.mp4", + "url": "https://livingdocs-videos-development.s3.amazonaws.com/2022/09/30/another-asset.mp4", + "size": 8633462, + "width": 1280, + "height": 720, + "duration": 35.241667, + "filename": "fire-fr.mp4", + "mimeType": "video/mp4" + }, + } + ] + } + ] + } +responses: + - code: "200" + endpoint: /api/v1/import/mediaLibrary + body: | + { + "mediaLibraryEntries": [ + { + "ok": true, + "status": 200, + "id": "custom-1", + "record": {} + } + ] + } + - code: "200" + endpoint: /api/v1/import/mediaLibrary (error cases for individual entries) + body: | + { + "mediaLibraryEntries": [ + { + "ok": false, + "correlation": "id: custom-1", + "status": 409, + "error": "UniqueIdViolation", + "error_details": { + "message": "id is not unique: 'custom-1'" + } + }, + { + "ok": false, + "correlation": "id: custom-2", + "status": 409, + "error": "UniqueIdViolation", + "error_details": { + "message": "externalId is not unique: 'external-1'" + } + }, + { + "ok": false, + "correlation": "id: custom-3", + "status": 400, + "error": "ValidationError", + "error_details": { + "message": "An asset with an externalId also requires a systemName" + } + }, + { + "ok": false, + "correlation": "id: custom-4", + "status": 400, + "error": "ValidationError", + "error_details": { + "message": 'Metadata validation failed.', + "errors": [{ + "metadataProperty": "title", + "message": "The value of '/title' must be string" + }] + } + } + ] + } diff --git a/content/reference/public-api/imports/videos.md b/content/reference/public-api/imports/videos.md index ceb599cb9..edf5b8a6e 100644 --- a/content/reference/public-api/imports/videos.md +++ b/content/reference/public-api/imports/videos.md @@ -7,196 +7,6 @@ menus: parent: Imports --- -{{< api-example - title="Import Videos" - scopes="public-api:write" ->}} +{{< api-example-resource file="import_videos.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/import/videos" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/video-import", - "videos": [ - { - "url": "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4", - "id": "123abc", - "fileName": "sample", - "metadata": { - "title": "sample video" - "credit": "LC" - } - } - ] - } -EOF -``` - ---endpoint-- -``` -POST api/v1/import/videos -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|systemName|string|x|Identifier for the system you are importing from, e.g. an archive.| -|webhook|uri||Endpoint at the importing system that gets notified by POST when import job is done. Notification contains the id of the import job, the state and an overview.| -|context|object||An object that is passed as context in the body of the request to the webhook. Limited to 8192 Bytes.| -|videos|array|x|An array of videos to import. Each entry is an object with the following keys, all of which are required:

**url:** a URL to a video file, must reference a video file with mimetype `video/*`.
**id:** a unique id (stored as externalId in Livingdocs) that identifies the video on your end, must be unique within your project
**fileName:** the title that the video should get in livingdocs
**metadata:** An object of metadata according to your project config| - -#### Example Request -```js -{ - "systemName": "identifier-for-your-system", - "webhook": "https://my-domain.com/webhooks/video-import", - "context": { - "myIdentifier": "some-identifier-sent-to-the-webhook" - }, - "videos": [ - { - "url": "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4", - "id": "123abc", - "fileName": "foo", - "metadata": { - "title": "sample video", - "credit": "LC" - } - } - ] -} -``` - ---description-- -The video import does both create and update videos. The import remembers the `externalId` / `systemName` pair and if an import matches an existing pair, it will update (Hint: consider how to rebuild the externalId when you want to update videos). The video import in Livingdocs is asynchronous. You post a batch of videos that you want to import and get back an id with which you can query later to get your result. - -##### Use Cases - -- [Initial import from a legacy system]({{< ref "/guides/setup/import-legacy-system-documents" >}}) - -##### Related - -- [Import Media Library Entries]({{< ref "/reference/public-api/imports/media-library-entries" >}}) - ---response-- -200 ---- -api/v1/import/videos ---- -```js -{ - "id": "25bzj8j" -} -``` - -{{< /api-example >}} - - -{{< api-example - title="Check Import Status for Videos" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/import/videos/status" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/import/videos/status -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|?id|string|x|The id that Livingdocs provided you for your prior call to "/import/videos"| - ---description-- -You can use this endpoint to check for the status and/or result of a video import. - ---response-- -200 ---- -api/v1/import/videos/status?id=25bzj8j ---- -```js -{ - "finished": true, - "state": "success", - "id": "25bzj8j", - "videos": [ - { - "status": "success", - "externalId": "external-unique-id-123", - "title": "my video", - "video": { - "mediaId": "jjiwhsf23kdk", - "originalUrl": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg", - "url": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "width": 100, - "height": 100, - "mimeType": "video/png", - "videoService": "imgix" - } - }, - { - "status": "skipped", - "reason": "already exists", - "externalId": "external-unique-id-234", - "title": "my second video", - "video": { - "mediaId": "jjiwhsf23wer", - "originalUrl": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "url": "https://livingdocs-videos.imgix.net/2019/11/21/a209790e-1549-46d9-b3c7-cefe28c7ea99.jpeg?auto=format", - "width": 100, - "height": 100, - "mimeType": "video/png", - "videoService": "imgix" - } - }, - { - "status": "failed", - "reason": "Could not upload video", - "externalId": "external-unique-id-345", - "title": "my third video" - } - ] -} -``` ------ -200 ---- -api/v1/import/videos/status?id=243kdc ---- -```js -{ - "finished": false, - "state": "started", - "id": "243kdc", - "startedAt": "2020-01-01 13:45:12" -} -``` ------ -200 ---- -api/v1/import/videos/status?id=098shjhv9 ---- -```js -{ - "finished": true, - "state": "failed", - "id": "098shjhv9" -} -``` - -{{< /api-example >}} +{{< api-example-resource file="check_video_import_status.yaml" >}} diff --git a/content/reference/public-api/media-library.md b/content/reference/public-api/media-library.md deleted file mode 100644 index fe2f52fd1..000000000 --- a/content/reference/public-api/media-library.md +++ /dev/null @@ -1,415 +0,0 @@ ---- -title: Media Library -weight: 9 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get a Single Media Library Entry" - scopes="public-api:read" ->}} - ---query-- - ---endpoint-- -``` -GET api/v1/mediaLibrary/:id -``` - ---parameters-- - ---description-- -Fetch a Media Library Entries by its `id`. - ---response-- -200 ---- -api/v1/mediaLibrary/:id ---- -```js -{ - "id": "asze63i9", - "version": 1, - "mediaType": "image", - "asset": { - "url": "https://livingdocs.io/img.jpg", - "mimeType": "image/jpeg", - "width": 1600, - "height": 900, - "size": 21000 - }, - "metadata": { - "title": "An Image" - }, - "createdAt": "2020-12-27T09:19:00.928Z", - "updatedAt": "2020-12-27T09:19:00.928Z" -} -``` - -{{< /api-example >}} - -{{< api-example - title="Patch a Media Library Entry" - scopes="public-api:write" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X PATCH "https://server.livingdocs.io/api/v1/mediaLibrary/:id" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -PATCH api/v1/mediaLibrary/:id -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|version|string||current mediaLibraryEntry version. When set on update the version is checked.| -|patches|array|x|an array of patches to execute. Each entry is an object with the following keys:

**operation** `setMetadataProperty`, `replaceAsset`, `revokeAsset`, `archive` or `removeAsset` ({{< added-in "release-2024-01" >}})
**propertyName** string of the propertyName (only for setMetadataProperty)
**value** string or object for the new value. If set to null or value is not set it will remove the property for setMetadataProperty. **required** for replaceAsset operation.
**locale** string of the asset to be removed (only in multilingual setups for removeAsset)| - -#### Example Request -```js -{ - "version": "1", - "patches": [ - { - // update a single metadata property - "operation": "setMetadataProperty", - "propertyName": "title", - "value": "updated title" - }, - { - // replace the asset - "operation": "replaceAsset", - "value": { - // the file with this key should exist in the configured storage - key: '2021/11/23/my-new-file.png', - url: 'https://example.com/my-new-file.png', - size: 10000, - width: 1000, - height: 800, - filename: 'my-new-file.png', - mimeType: 'image/png' - } - }, - { - // revoke the asset - "operation": "revokeAsset" - }, - { - // archives a Media Library Entry - "operation": "archive" - }, - { - // removes a translated asset (the default locale asset cannot be removed) - "operation": "removeAsset", - "locale": "en" - } - ] -} -``` - ---description-- -Patch a Media Library Entry by its `id`. - -##### Use Cases - -- Enhancing MediaLibraryEntries. For example, update the metadata after transcoding a video or analyzing the media with an external service. -- When having a separate DAM - update Livingdocs Media Library Entry - ---response-- -200 ---- -api/v1/mediaLibrary/:id ---- -```js -{ - "status": 200 -} -``` ------ -400 ---- -api/v1/mediaLibrary/:id ---- -```js -{ - "status": 400, - "error": "Bad Request", - "error_details": { - "patches.0.operation": "No enum match for: \"notExistingOperation\"" - } -} -``` ------ -404 ---- -api/v1/mediaLibrary/:id ---- -```js -{ - "status": 404, - "error": "Not Found", - "error_details": { - "name": "NotFound", - "message": "MediaLibrary Entry does not exist (id: 'yLBGtTjWN4ba')" - } -} -``` ------ -409 ---- -api/v1/mediaLibrary/:id ---- -```js -{ - "status": 409, - "error": "Conflict", - "error_details": { - "name": "Conflict", - "message": "Version: Expected 36 to be equal to 1" - } -} -``` - -{{< /api-example >}} - -{{< api-example - title="Get Media Library Entries" - scopes="public-api:read" ->}} - ---query-- - ---endpoint-- -``` -GET api/v1/mediaLibrary?ids= -``` -``` -GET api/v1/mediaLibrary?externalId=&systemName= -``` - ---parameters-- - ---description-- -Fetch multiple Media Library Entries by their `id`s or `externalId`s - ---response-- -200 ---- -api/v1/mediaLibrary?ids=asze63i9,2er11b3i ---- -```js -{ - "mediaLibraryEntries": [ - { - "id": "asze63i9", - "version": 1, - "mediaType": "image", - "asset": { - "url": "https://livingdocs.io/img.jpg", - "mimeType": "image/jpeg", - "width": 1600, - "height": 900, - "size": 21000 - }, - "metadata": { - "title": "An Image" - }, - "createdAt": "2020-12-27T09:19:00.928Z", - "updatedAt": "2020-12-27T09:19:00.928Z" - }, - { - "id": "2er11b3i", - "version": 1, - "mediaType": "image", - "asset": { - "url": "https://livingdocs.io/img2.jpg", - "mimeType": "image/jpeg", - "width": 1600, - "height": 900, - "size": 21000 - }, - "metadata": { - "title": "An Other Image" - }, - "createdAt": "2020-12-27T09:19:00.928Z", - "updatedAt": "2020-12-27T09:19:00.928Z" - } - ] -} -``` ------ -200 ---- -api/v1/mediaLibrary?externalId=ex-1&systemName=externalSystem ---- -```js -{ - "mediaLibraryEntries": [ - { - "id": "a77ei8nm", - "version": 1, - "systemName": "externalSystem", - "externalId": "ex-1", - "mediaType": "image", - "asset": { - "url": "https://livingdocs.io/img.jpg", - "mimeType": "image/jpeg", - "width": 1600, - "height": 900, - "size": 21000 - }, - "metadata": { - "title": "An Image" - }, - "createdAt": "2020-12-27T09:19:00.928Z", - "updatedAt": "2020-12-27T09:19:00.928Z" - } - ] -} -``` - -{{< /api-example >}} - -{{< api-example - title="Get Incoming Publication References for a Media Library Entry" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/mediaLibrary/:mediaId/incomingDocumentReferences" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/mediaLibrary/:mediaId/incomingDocumentReferences -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:mediaId|string|x|| -|?limit|integer||A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer||An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- - -This endpoint returns all publications which link to this Media Library Entry (via content or metadata) - -##### Use Cases - -- Useful to know if the Media Library Entry is in use when revoking or archiving - ---response-- -200 ---- ---- -```js -[ - { - "id": 2, - "references": [ - { - "id": "9fKagDCiN6sb", - "type": "image", - "location": "image-directive", - "componentId": "doc-1ev8345oj0", - "componentName": "image", - "directiveName": "image" - }, - { - "id": "9fKagDCiN6sb", - "type": "image", - "location": "metadata", - "propertyName": "teaserImage" - } - ] - }, - { - "id": 3, - "references": [ - { - "id": "9fKagDCiN6sb", - "type": "image", - "location": "image-directive", - "componentId": "doc-1euq8lq1o0", - "componentName": "image", - "directiveName": "image" - }, - { - "id": "9fKagDCiN6sb", - "type": "image", - "location": "metadata", - "propertyName": "teaserImage" - } - ] - } -] -``` - -{{< /api-example >}} - -{{< api-example - title="Get Incoming Media References for a Media Library Entry" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/mediaLibrary/:mediaId/incomingMediaReferences" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/mediaLibrary/:mediaId/incomingMediaReferences -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:mediaId|string|x|| -|?limit|integer||A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer||An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- - -This endpoint returns all Media Library Entries which link to this Media Library Entry (via metadata) - ---response-- -200 ---- ---- -```js -[ - { - "id": "B1LPgANhJFpo", - "references": [ - { - "id": "9fKagDCiN6sb", - "type": "image", - "location": "metadata", - "propertyName": "imageLink" - } - ] - } -] -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/media-library/_index.md b/content/reference/public-api/media-library/_index.md new file mode 100644 index 000000000..207a70b36 --- /dev/null +++ b/content/reference/public-api/media-library/_index.md @@ -0,0 +1,18 @@ +--- +title: Media Library +weight: 9 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_media_library_entry.yaml" >}} + +{{< api-example-resource file="patch_media_library_entry.yaml" >}} + +{{< api-example-resource file="get_media_library_entries.yaml" >}} + +{{< api-example-resource file="get_media_library_incoming_document_references.yaml" >}} + +{{< api-example-resource file="get_media_library_incoming_media_references.yaml" >}} diff --git a/content/reference/public-api/media-library/get_media_library_entries.yaml b/content/reference/public-api/media-library/get_media_library_entries.yaml new file mode 100644 index 000000000..dda79d722 --- /dev/null +++ b/content/reference/public-api/media-library/get_media_library_entries.yaml @@ -0,0 +1,89 @@ +title: Get Media Library Entries +description: | + Fetch multiple Media Library Entries by their `id`s or `externalId`s + +scopes: public-api:read +endpoint: + method: GET + path: /api/v1/mediaLibrary +parameters: + - name: ids + type: string + required: false + notes: "Comma separated list of media library entry ids" + - name: externalId + type: string + required: false + notes: "External id of the media library entry" + - name: systemName + type: string + required: false + notes: "System name of the media library entry" +responses: + - code: "200" + endpoint: /api/v1/mediaLibrary?ids=asze63i9,2er11b3i + body: | + { + "mediaLibraryEntries": [ + { + "id": "asze63i9", + "version": 1, + "mediaType": "image", + "asset": { + "url": "https://livingdocs.io/img.jpg", + "mimeType": "image/jpeg", + "width": 1600, + "height": 900, + "size": 21000 + }, + "metadata": { + "title": "An Image" + }, + "createdAt": "2020-12-27T09:19:00.928Z", + "updatedAt": "2020-12-27T09:19:00.928Z" + }, + { + "id": "2er11b3i", + "version": 1, + "mediaType": "image", + "asset": { + "url": "https://livingdocs.io/img2.jpg", + "mimeType": "image/jpeg", + "width": 1600, + "height": 900, + "size": 21000 + }, + "metadata": { + "title": "An Other Image" + }, + "createdAt": "2020-12-27T09:19:00.928Z", + "updatedAt": "2020-12-27T09:19:00.928Z" + } + ] + } + - code: "200" + endpoint: /api/v1/mediaLibrary?externalId=ex-1&systemName=externalSystem + body: | + { + "mediaLibraryEntries": [ + { + "id": "a77ei8nm", + "version": 1, + "systemName": "externalSystem", + "externalId": "ex-1", + "mediaType": "image", + "asset": { + "url": "https://livingdocs.io/img.jpg", + "mimeType": "image/jpeg", + "width": 1600, + "height": 900, + "size": 21000 + }, + "metadata": { + "title": "An Image" + }, + "createdAt": "2020-12-27T09:19:00.928Z", + "updatedAt": "2020-12-27T09:19:00.928Z" + } + ] + } diff --git a/content/reference/public-api/media-library/get_media_library_entry.yaml b/content/reference/public-api/media-library/get_media_library_entry.yaml new file mode 100644 index 000000000..27d167fd2 --- /dev/null +++ b/content/reference/public-api/media-library/get_media_library_entry.yaml @@ -0,0 +1,29 @@ +title: Get a Single Media Library Entry +description: | + Fetch a Media Library Entries by its `id`. + +scopes: public-api:read +endpoint: + method: GET + path: /api/v1/mediaLibrary/:id +responses: + - code: "200" + endpoint: /api/v1/mediaLibrary/:id + body: | + { + "id": "asze63i9", + "version": 1, + "mediaType": "image", + "asset": { + "url": "https://livingdocs.io/img.jpg", + "mimeType": "image/jpeg", + "width": 1600, + "height": 900, + "size": 21000 + }, + "metadata": { + "title": "An Image" + }, + "createdAt": "2020-12-27T09:19:00.928Z", + "updatedAt": "2020-12-27T09:19:00.928Z" + } diff --git a/content/reference/public-api/media-library/get_media_library_incoming_document_references.yaml b/content/reference/public-api/media-library/get_media_library_incoming_document_references.yaml new file mode 100644 index 000000000..8305edbb0 --- /dev/null +++ b/content/reference/public-api/media-library/get_media_library_incoming_document_references.yaml @@ -0,0 +1,72 @@ +title: Get Incoming Publication References for a Media Library Entry +description: | + This endpoint returns all publications which link to this Media Library Entry (via content or metadata) + +useCases: | + - Useful to know if the Media Library Entry is in use when revoking or archiving + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/mediaLibrary/:mediaId/incomingDocumentReferences" \ + -H "Authorization: Bearer $ACCESS_TOKEN" + +endpoint: + method: GET + path: /api/v1/mediaLibrary/:mediaId/incomingDocumentReferences +parameters: + - name: :mediaId + type: string + required: true + notes: "" + - name: ?limit + type: integer + required: false + notes: A limit for how much published documents to retrieve. Defaults to 100. Max. 100. + - name: ?offset + type: integer + required: false + notes: An offset into the query. Useful when getting more than 100 results (pagination). +responses: + - code: "200" + body: | + [ + { + "id": 2, + "references": [ + { + "id": "9fKagDCiN6sb", + "type": "image", + "location": "image-directive", + "componentId": "doc-1ev8345oj0", + "componentName": "image", + "directiveName": "image" + }, + { + "id": "9fKagDCiN6sb", + "type": "image", + "location": "metadata", + "propertyName": "teaserImage" + } + ] + }, + { + "id": 3, + "references": [ + { + "id": "9fKagDCiN6sb", + "type": "image", + "location": "image-directive", + "componentId": "doc-1euq8lq1o0", + "componentName": "image", + "directiveName": "image" + }, + { + "id": "9fKagDCiN6sb", + "type": "image", + "location": "metadata", + "propertyName": "teaserImage" + } + ] + } + ] diff --git a/content/reference/public-api/media-library/get_media_library_incoming_media_references.yaml b/content/reference/public-api/media-library/get_media_library_incoming_media_references.yaml new file mode 100644 index 000000000..32cf6a0a3 --- /dev/null +++ b/content/reference/public-api/media-library/get_media_library_incoming_media_references.yaml @@ -0,0 +1,40 @@ +title: Get Incoming Media References for a Media Library Entry +description: | + This endpoint returns all Media Library Entries which link to this Media Library Entry (via metadata) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/mediaLibrary/:mediaId/incomingMediaReferences" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/mediaLibrary/:mediaId/incomingMediaReferences +parameters: + - name: :mediaId + type: string + required: true + - name: ?limit + type: integer + required: false + notes: A limit for how much published documents to retrieve. Defaults to 100. Max. 100. + - name: ?offset + type: integer + required: false + notes: An offset into the query. Useful when getting more than 100 results (pagination). +responses: + - code: "200" + body: | + [ + { + "id": "B1LPgANhJFpo", + "references": [ + { + "id": "9fKagDCiN6sb", + "type": "image", + "location": "metadata", + "propertyName": "imageLink" + } + ] + } + ] diff --git a/content/reference/public-api/media-library/patch_media_library_entry.yaml b/content/reference/public-api/media-library/patch_media_library_entry.yaml new file mode 100644 index 000000000..2a82ae678 --- /dev/null +++ b/content/reference/public-api/media-library/patch_media_library_entry.yaml @@ -0,0 +1,111 @@ +title: Patch a Media Library Entry +description: | + Patch a Media Library Entry by its `id`. + +useCases: | + - Enhancing MediaLibraryEntries. For example, update the metadata after transcoding a video or analyzing the media with an external service. + - When having a separate DAM - update Livingdocs Media Library Entry + +scopes: public-api:write +query: | + ACCESS_TOKEN=ey1234 + curl -k -X PATCH "https://server.livingdocs.io/api/v1/mediaLibrary/:id" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: PATCH + path: /api/v1/mediaLibrary/:id +parameters: + - name: version + type: string + required: false + notes: "current mediaLibraryEntry version. When set on update the version is checked." + - name: patches + type: array + required: true + notes: | + An array of patches to execute. Each entry is an object with the following keys: + - **operation** `setMetadataProperty`, `replaceAsset`, `revokeAsset`, `archive` or `removeAsset` ({{< added-in "release-2024-01" >}}) + - **propertyName** string of the propertyName (only for setMetadataProperty) + - **value** string or object for the new value. If set to null or value is not set it will remove the property for setMetadataProperty. **required** for replaceAsset operation. + - **locale** string of the asset to be removed (only in multilingual setups for removeAsset) + +example_request: | + { + "version": "1", + "patches": [ + { + // update a single metadata property + "operation": "setMetadataProperty", + "propertyName": "title", + "value": "updated title" + }, + { + // replace the asset + "operation": "replaceAsset", + "value": { + // the file with this key should exist in the configured storage + key: '2021/11/23/my-new-file.png', + url: 'https://example.com/my-new-file.png', + size: 10000, + width: 1000, + height: 800, + filename: 'my-new-file.png', + mimeType: 'image/png' + } + }, + { + // revoke the asset + "operation": "revokeAsset" + }, + { + // archives a Media Library Entry + "operation": "archive" + }, + { + // removes a translated asset (the default locale asset cannot be removed) + "operation": "removeAsset", + "locale": "en" + } + ] + } + +responses: + - code: "200" + endpoint: /api/v1/mediaLibrary/:id + body: | + { + "status": 200 + } + - code: "400" + endpoint: /api/v1/mediaLibrary/:id + body: | + { + "status": 400, + "error": "Bad Request", + "error_details": { + "patches.0.operation": "No enum match for: \"notExistingOperation\"" + } + } + - code: "404" + endpoint: /api/v1/mediaLibrary/:id + body: | + { + "status": 404, + "error": "Not Found", + "error_details": { + "name": "NotFound", + "message": "MediaLibrary Entry does not exist (id: 'yLBGtTjWN4ba')" + } + } + - code: "409" + endpoint: /api/v1/mediaLibrary/:id + body: | + { + "status": 409, + "error": "Conflict", + "error_details": { + "name": "Conflict", + "message": "Version: Expected 36 to be equal to 1" + } + } diff --git a/content/reference/public-api/menus.md b/content/reference/public-api/menus.md deleted file mode 100644 index 8b4e20408..000000000 --- a/content/reference/public-api/menus.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Menus -weight: 12 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get Menus for a Channel ({{< deprecated-in \"release-2024-11\" >}})" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/menus/:channelHandle" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -{{< deprecated-in "release-2024-11" >}} -``` -GET api/v1/menus/:channelHandle -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|:channelHandle|string|The handle of the channel for which you want to get the events.| -|?handle|string|Handle of the menu to retrieve.| - ---description-- - -Attention: - -Menus and this endpoint should not be used anymore. The [Menu Tool]({{< ref "/guides/editor/menus" >}}) provides a better developer and user experience for managing menus. - -Menu items can be of three types: - -- uri for arbitrary URIs, mainly used for URLs -- path for internal paths, such as when the menu item should link to an article or page -- document is the same as path except it is used when routing is disabled - - - -##### Use Cases - -- Get menus for deliveries - ---response-- -200 ---- -api/v1/menus/web ---- -```js -[ - { - "version": 8, - "label": "My Menu", - "maxDepth": 1, - "nodes": [ - { - "id": "11111111-0601-4c2b-a3b5-4da19b6d3bde", - "label": "My Index", - "path": "/", - "type": "uri", - "target": "_self", - "nodes": [ - { - "id": "22222222-0601-4c2b-a3b5-4da19b6d3bde", - "documentId": 71, - "label": "Other Page", - "type": "path", - "path": "/page/some-other-page", - "nodes": [] - } - ] - }, - { - "id": "33333333-0601-4c2b-a3b5-4da19b6d3bde", - "label": "Arbitrary URL", - "type": "uri", - "uri": "http://example.com", - "nodes": [] - }, - { - "id": "44444444-0601-4c2b-a3b5-4da19b6d3bde", - "label": "Other But External URL Link", - "type": "uri", - "uri": "http://foo.bar", - "target": "_blank", - "nodes": [] - } - ] - } -] -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/menus/_index.md b/content/reference/public-api/menus/_index.md new file mode 100644 index 000000000..c4904aaf5 --- /dev/null +++ b/content/reference/public-api/menus/_index.md @@ -0,0 +1,10 @@ +--- +title: Menus +weight: 12 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_menus.yaml" >}} diff --git a/content/reference/public-api/menus/get_menus.yaml b/content/reference/public-api/menus/get_menus.yaml new file mode 100644 index 000000000..d7b7a017c --- /dev/null +++ b/content/reference/public-api/menus/get_menus.yaml @@ -0,0 +1,76 @@ +title: Get Menus for a Channel ({{< deprecated-in "release-2024-11" >}}) +description: | + Menu items can be of three types: + - uri for arbitrary URIs, mainly used for URLs + - path for internal paths, such as when the menu item should link to an article or page + - document is the same as path except it is used when routing is disabled + +useCases: | + - Get menus for deliveries + +deprecation: + since: release-2023-03 + note: Menus and this endpoint should not be used anymore. The [Menu Tool]({{< ref "/guides/editor/menus" >}}) provides a better developer and user experience for managing menus. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/menus/:channelHandle" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/menus/:channelHandle +parameters: + - name: :channelHandle + type: string + required: true + notes: "The handle of the channel for which you want to get the events." + - name: ?handle + type: string + required: false + notes: "Handle of the menu to retrieve." +responses: + - code: "200" + endpoint: /api/v1/menus/web + body: | + [ + { + "version": 8, + "label": "My Menu", + "maxDepth": 1, + "nodes": [ + { + "id": "11111111-0601-4c2b-a3b5-4da19b6d3bde", + "label": "My Index", + "path": "/", + "type": "uri", + "target": "_self", + "nodes": [ + { + "id": "22222222-0601-4c2b-a3b5-4da19b6d3bde", + "documentId": 71, + "label": "Other Page", + "type": "path", + "path": "/page/some-other-page", + "nodes": [] + } + ] + }, + { + "id": "33333333-0601-4c2b-a3b5-4da19b6d3bde", + "label": "Arbitrary URL", + "type": "uri", + "uri": "http://example.com", + "nodes": [] + }, + { + "id": "44444444-0601-4c2b-a3b5-4da19b6d3bde", + "label": "Other But External URL Link", + "type": "uri", + "uri": "http://foo.bar", + "target": "_blank", + "nodes": [] + } + ] + } + ] diff --git a/content/reference/public-api/project.md b/content/reference/public-api/project.md deleted file mode 100644 index ba141e29c..000000000 --- a/content/reference/public-api/project.md +++ /dev/null @@ -1,749 +0,0 @@ ---- -title: Project Configuration -weight: 2 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get Project Config" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/projectConfig" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET /api/v1/projectConfig -``` - -{{< deprecated-in "release-2023-03" >}} -``` -GET api/v1/channelConfig -``` - ---parameters-- - ---description-- - -This endpoint returns the [Project Config]({{< ref "/reference/project-config" >}}). - -##### Use Cases - -- Used by [Livingdocs CLI]({{< ref "/reference/cli" >}}) to download the Project Config - ---response-- -200 ---- ---- -```js -{ - "v": 2, - "$baseRevision": 28, - "settings": { - "handle": "service", - "languages": { - "available": [ - { - "label": "German", - "locale": "de" - } - ], - "defaultLanguage": { - "label": "German", - "locale": "de" - }, - "requiredOnCreation": true, - "translationWorkflow": true - }, - "editMode": "default" - }, - "editorSettings": { - "mainNavigation": [ - { - "handle": "articleManagement", - "label": "Articles", - "dashboard": "articleManagement", - "icon": "file-document-edit" - }, - { - "liItem": "mediaLibrary" - } - ], - "dashboards": [ - { - "handle": "articleManagement", - "type": "tableDashboard", - "pageTitle": "Article Management", - "baseFilters": [ - { - "type": "documentType", - "value": "article" - } - ], - "displayFilters": [ - "contentType" - ], - "sort": "-updated_at", - "columns": [ - { - "label": "Article", - "minWidth": 375, - "growFactor": 2, - "priority": 1, - "componentName": "liTableDashboardCellMain", - "componentOptions": { - "image": { - "metadataPropertyName": "teaserImage" - }, - "clampTitle": false, - "showContentType": true - }, - "editable": false - }, - { - "label": "Description", - "metadataPropertyName": "description", - "editable": true, - "minWidth": 150, - "growFactor": 1, - "priority": 5 - } - ] - } - ] - }, - "contentTypes": [ - { - "handle": "regular", - "documentType": "article", - "info": { - "label": "Regular Article" - }, - "components": [ - { - "name": "web-teaser" - }, - { - "name": "title" - }, - { - "name": "p" - } - ], - "editorWrapper": "
", - "defaultContent": [ - { - "component": "title" - } - ], - "metadata": [ - { - "handle": "title", - "type": "li-text", - "config": { - "minLength": 5, - "maxLength": 200, - "recommendedMinLength": 50, - "recommendedMaxLength": 150, - "allowNewlines": false, - "required": false, - "hideFromForm": false, - "translatable": false - }, - "ui": { - "config": { - "readOnly": false - } - } - }, - { - "handle": "description", - "type": "li-text", - "config": { - "allowNewlines": true, - "required": false, - "hideFromForm": false, - "translatable": false - }, - "ui": { - "config": { - "readOnly": false - } - } - } - ], - "metadataGroups": [ - { - "label": "General", - "properties": [ - "title", - "description" - ], - "expanded": true - } - ] - } - ], - "mediaTypes": [ - { - "type": "mediaImage", - "handle": "image", - "info": { - "label": "Images", - "description": "" - }, - "asset": { - "translatable": true, - "replaceable": true - }, - "metadata": [ - { - "handle": "title", - "type": "li-text", - "config": { - "required": true, - "requiredErrorMessage": "Please provide a title", - "maxLength": 200, - "translatable": true, - "index": true, - "hideFromForm": false - }, - "ui": { - "config": { - "readOnly": false - } - } - } - ], - "editor": { - "dashboard": { - "displayFilters": [ - { - "filterName": "liDateTimeRange" - } - ], - "card": { - "name": "myImageCard" - } - }, - "managementDashboard": { - "displayFilters": [ - { - "filterName": "liDateTimeRange" - }, - { - "filterName": "category" - } - ] - } - } - } - ], - "designSettings": { - "assets": { - "css": [ - "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" - ] - }, - "mediaRendering": { - "backgroundImage": { - "defaultWidth": 1000 - }, - "srcSet": { - "defaultWidth": 1000, - "widths": [ - 1000, - 600, - 300 - ], - "sizes": [ - "100vw" - ] - }, - "video": { - "muted": true - } - }, - "componentGroups": [ - { - "name": "text", - "label": "Text", - "components": [ - "title", - "section-title", - "p" - ] - } - ], - "defaultComponents": { - "paragraph": "p", - "image": "image", - "video": "video-include" - }, - "fieldExtractor": [ - { - "identifier": "title", - "type": "text", - "matches": [ - "title.title" - ] - } - ], - "componentProperties": [ - { - "name": "depth", - "label": "Shadow", - "type": "option", - "value": "z-depth-2" - } - ], - "namedCrops": [ - { - "handle": "mobile", - "label": "Mobile", - "description": "this image will be shown on small screens", - "recommendedRatios": [ - "1:1", - "16:9" - ] - } - ] - }, - "components": [ - { - "name": "title", - "label": "Title", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_header_simple.svg", - "directives": [ - { - "type": "editable", - "name": "title", - "minLength": 1, - "maxLength": 150, - "recommendedMinLength": 20, - "recommendedMaxLength": 80, - "plainText": true - } - ], - "html": "

\n Title\n

" - }, - { - "name": "p", - "label": "Paragraph", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_text.svg", - "html": "

\n Paragraph\n

" - } - ], - "categories": [ - { - "id": "123abc", - "label": "Home", - "path": "/", - "metadata": { - "adId": "foo" - } - } - ], - "deliveries": [ - { - "handle": "web", - "label": "Website", - "isPrimary": true, - "icon": "book-open", - "url": { - "origin": "https://livingdocs.io", - "pathPattern": "/doc/:id" - } - } - ], - "notifications": { - "actionGroups": [ - { - "handle": "all", - "label": "All Events", - "description": "Comments, Tasks, Publish and delete", - "actions": [ - "task.change", - "document.publish", - "document.unpublish", - "document.copy", - "document.delete", - "document.transform", - "comment.add", - "comment.resolve" - ] - } - ], - "notifyTaskRequester": true, - "autoSubscribeOwner": { - "enabled": true, - "actionGroup": "all" - } - }, - "import": { - "allowedProjects": [ - { - "handle": "service-clone" - } - ] - }, - "export": { - "allowedProjects": [ - { - "handle": "service-clone" - } - ] - }, - "externalSystems": [ - { - "handle": "myExternalSystem", - "label": "My System", - "url": { - "origin": "https://example.com", - "pathPattern": "/{{metadata.myExternalSystemId}}" - }, - "icon": "track-light", - "isPrimary": false - } - ] -} -``` - -{{< /api-example >}} - - -{{< api-example - title="Get Project Configuration ({{< deprecated-in \"release-2023-03\" >}})" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/project" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/project -``` - ---parameters-- - ---description-- - -Deprecated: Use `GET api/v1/projectConfig` instead. - ---response-- -200 ---- ---- -```js -{ - "projectId": 1, - "name": "b5c5f804-7927-44e2-a3fd-f97bc6784dab", - "label": "Daily Planet", - "defaultChannelId": 1, - "channels": [ - { - "channelId": 1, - "channelHandle": "web", - "label": "Web", - "designName": "timeline", - "designVersion": "1.1.0", - "editMode": "default", - "contentTypeHandles": [ - "regular", - "page" - ], - "contentTypes": [ - { - "contentTypeHandle": "regular", - "documentType": "article", - "metadata": [ - { - "name": "title", - "plugin": "li-text" - }, - { - "name": "author", - "plugin": "li-text" - }, - { - "name": "teaserImage", - "plugin": "li-image" - }, - { - "name": "dependencies", - "plugin": "li-dependencies" - }, - { - "name": "tasks", - "plugin": "li-tasks" - } - ], - "renditionHandles": [ - "web", - "mobile" - ] - }, - { - "contentTypeHandle": "page", - "documentType": "page", - "metadata": [ - { - "name": "title", - "plugin": "li-text" - }, - { - "name": "dependencies", - "plugin": "li-dependencies" - }, - { - "name": "routing", - "plugin": "li-default-routing" - } - ], - "renditionHandles": [ - "web" - ] - } - ] - } - ] -} -``` - -{{< /api-example >}} - -{{< api-example - title="Get Channel Configuration ({{< deprecated-in \"release-2023-03\" >}})" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/channels/:channelHandle" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/channels/:channelHandle -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|:channelHandle|string|Optional channelHandle. Will return first channel of a project if none is passed.| - ---description-- - -Deprecated: Use `GET api/v1/projectConfig` instead. - ---response-- -200 ---- ---- -```js -{ - "channelId": 1, - "channelHandle": "web", - "label": "Web", - "designName": "timeline", - "designVersion": "1.1.0", - "editMode": "default", - "contentTypeHandles": [ - "regular", - "page" - ], - "contentTypes": [ - { - "contentTypeHandle": "regular", - "documentType": "article", - "metadata": [ - { - "name": "title", - "plugin": "li-text" - }, - { - "name": "author", - "plugin": "li-text" - }, - { - "name": "teaserImage", - "plugin": "li-image" - }, - { - "name": "dependencies", - "plugin": "li-dependencies" - }, - { - "name": "tasks", - "plugin": "li-tasks" - } - ], - "renditionHandles": [ - "web", - "mobile" - ] - }, - { - "contentTypeHandle": "page", - "documentType": "page", - "metadata": [ - { - "name": "title", - "plugin": "li-text" - }, - { - "name": "dependencies", - "plugin": "li-dependencies" - }, - { - "name": "routing", - "plugin": "li-default-routing" - } - ], - "renditionHandles": [ - "web" - ] - } - ] -} -``` - -{{< /api-example >}} - -{{< api-example - title="Get Design Configuration" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/design/:designVersion" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/design/:designVersion -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|:designVersion|string|Optional design version. Will take the current design version of a channel if none is passed.| - ---description-- - -##### Use Cases - -- Load the appropriate Design Version for a document - ---response-- -200 ---- ---- -```js -{ - "name": "p:1:1", - "version": "1.0.0", - "assets": { - "css": [ - "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" - ] - }, - "defaultComponents": { - "paragraph": "p", - "image": "image" - }, - "groups": [ - { - "name": "content", - "label": "Components", - "components": [ - "title", - "p", - "image", - "insta" - ] - } - ], - "componentProperties": {}, - "metadata": [ - { - "identifier": "title", - "type": "text", - "matches": [ - "title.title" - ] - } - ], - "components": [ - { - "name": "title", - "label": "Title", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_header_simple.svg", - "html": "

\n Title\n

", - "directives": {} - }, - { - "name": "p", - "label": "Paragraph", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_text.svg", - "html": "

\n Paragraph\n

", - "directives": {} - }, - { - "name": "image", - "label": "Image", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_image.svg", - "directives": { - "img": { - "name": "img", - "type": "image", - "imageRatios": [ - "16:9", - "1:1", - "4:3", - "3:4" - ] - } - }, - "html": "" - }, - { - "name": "insta", - "label": "Instagram", - "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_image.svg", - "directives": { - "insta": { - "name": "insta", - "type": "include", - "service": "instagram" - } - }, - "html": "
\n
Instagram Include
\n
" - } - ] -} -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/project/_index.md b/content/reference/public-api/project/_index.md new file mode 100644 index 000000000..ae8822fd4 --- /dev/null +++ b/content/reference/public-api/project/_index.md @@ -0,0 +1,16 @@ +--- +title: Project Configuration +weight: 2 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_project_config.yaml" >}} + +{{< api-example-resource file="get_project_configuration.yaml" >}} + +{{< api-example-resource file="get_channel_configuration.yaml" >}} + +{{< api-example-resource file="get_design_configuration.yaml" >}} diff --git a/content/reference/public-api/project/get_channel_configuration.yaml b/content/reference/public-api/project/get_channel_configuration.yaml new file mode 100644 index 000000000..485d5cc14 --- /dev/null +++ b/content/reference/public-api/project/get_channel_configuration.yaml @@ -0,0 +1,89 @@ +title: Get Channel Configuration ({{< deprecated-in "release-2023-03" >}}) + +deprecation: + since: release-2023-03 + note: Use `GET /api/v1/projectConfig` instead. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/channels/:channelHandle" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/channels/:channelHandle +parameters: + - name: :channelHandle + type: string + required: false + notes: Optional channelHandle. Will return first channel of a project if none is passed. + +deprecated: release-2023-03 +responses: + - code: "200" + body: | + { + "channelId": 1, + "channelHandle": "web", + "label": "Web", + "designName": "timeline", + "designVersion": "1.1.0", + "editMode": "default", + "contentTypeHandles": [ + "regular", + "page" + ], + "contentTypes": [ + { + "contentTypeHandle": "regular", + "documentType": "article", + "metadata": [ + { + "name": "title", + "plugin": "li-text" + }, + { + "name": "author", + "plugin": "li-text" + }, + { + "name": "teaserImage", + "plugin": "li-image" + }, + { + "name": "dependencies", + "plugin": "li-dependencies" + }, + { + "name": "tasks", + "plugin": "li-tasks" + } + ], + "renditionHandles": [ + "web", + "mobile" + ] + }, + { + "contentTypeHandle": "page", + "documentType": "page", + "metadata": [ + { + "name": "title", + "plugin": "li-text" + }, + { + "name": "dependencies", + "plugin": "li-dependencies" + }, + { + "name": "routing", + "plugin": "li-default-routing" + } + ], + "renditionHandles": [ + "web" + ] + } + ] + } diff --git a/content/reference/public-api/project/get_design_configuration.yaml b/content/reference/public-api/project/get_design_configuration.yaml new file mode 100644 index 000000000..1f55748d0 --- /dev/null +++ b/content/reference/public-api/project/get_design_configuration.yaml @@ -0,0 +1,102 @@ +title: Get Design Configuration +useCases: | + - Load the appropriate Design Version for a document + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/design/:designVersion" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/design/:designVersion +parameters: + - name: :designVersion + type: string + required: false + notes: "Optional design version. Will take the current design version of a channel if none is passed." +responses: + - code: "200" + body: | + { + "name": "p:1:1", + "version": "1.0.0", + "assets": { + "css": [ + "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" + ] + }, + "defaultComponents": { + "paragraph": "p", + "image": "image" + }, + "groups": [ + { + "name": "content", + "label": "Components", + "components": [ + "title", + "p", + "image", + "insta" + ] + } + ], + "componentProperties": {}, + "metadata": [ + { + "identifier": "title", + "type": "text", + "matches": [ + "title.title" + ] + } + ], + "components": [ + { + "name": "title", + "label": "Title", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_header_simple.svg", + "html": "

\n Title\n

", + "directives": {} + }, + { + "name": "p", + "label": "Paragraph", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_text.svg", + "html": "

\n Paragraph\n

", + "directives": {} + }, + { + "name": "image", + "label": "Image", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_image.svg", + "directives": { + "img": { + "name": "img", + "type": "image", + "imageRatios": [ + "16:9", + "1:1", + "4:3", + "3:4" + ] + } + }, + "html": "" + }, + { + "name": "insta", + "label": "Instagram", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_image.svg", + "directives": { + "insta": { + "name": "insta", + "type": "include", + "service": "instagram" + } + }, + "html": "
\n
Instagram Include
\n
" + } + ] + } diff --git a/content/reference/public-api/project/get_project_config.yaml b/content/reference/public-api/project/get_project_config.yaml new file mode 100644 index 000000000..0e2f12d6b --- /dev/null +++ b/content/reference/public-api/project/get_project_config.yaml @@ -0,0 +1,391 @@ +title: Get Project Config +description: | + This endpoint returns the [Project Config]({{< ref "/reference/project-config" >}}). + +useCases: | + - Used by [Livingdocs CLI]({{< ref "/reference/cli" >}}) to download the Project Config + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/projectConfig" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/projectConfig +deprecated_endpoints: + - GET api/v1/channelConfig +responses: + - code: "200" + body: | + { + "v": 2, + "$baseRevision": 28, + "settings": { + "handle": "service", + "languages": { + "available": [ + { + "label": "German", + "locale": "de" + } + ], + "defaultLanguage": { + "label": "German", + "locale": "de" + }, + "requiredOnCreation": true, + "translationWorkflow": true + }, + "editMode": "default" + }, + "editorSettings": { + "mainNavigation": [ + { + "handle": "articleManagement", + "label": "Articles", + "dashboard": "articleManagement", + "icon": "file-document-edit" + }, + { + "liItem": "mediaLibrary" + } + ], + "dashboards": [ + { + "handle": "articleManagement", + "type": "tableDashboard", + "pageTitle": "Article Management", + "baseFilters": [ + { + "type": "documentType", + "value": "article" + } + ], + "displayFilters": [ + "contentType" + ], + "sort": "-updated_at", + "columns": [ + { + "label": "Article", + "minWidth": 375, + "growFactor": 2, + "priority": 1, + "componentName": "liTableDashboardCellMain", + "componentOptions": { + "image": { + "metadataPropertyName": "teaserImage" + }, + "clampTitle": false, + "showContentType": true + }, + "editable": false + }, + { + "label": "Description", + "metadataPropertyName": "description", + "editable": true, + "minWidth": 150, + "growFactor": 1, + "priority": 5 + } + ] + } + ] + }, + "contentTypes": [ + { + "handle": "regular", + "documentType": "article", + "info": { + "label": "Regular Article" + }, + "components": [ + { + "name": "web-teaser" + }, + { + "name": "title" + }, + { + "name": "p" + } + ], + "editorWrapper": "
", + "defaultContent": [ + { + "component": "title" + } + ], + "metadata": [ + { + "handle": "title", + "type": "li-text", + "config": { + "minLength": 5, + "maxLength": 200, + "recommendedMinLength": 50, + "recommendedMaxLength": 150, + "allowNewlines": false, + "required": false, + "hideFromForm": false, + "translatable": false + }, + "ui": { + "config": { + "readOnly": false + } + } + }, + { + "handle": "description", + "type": "li-text", + "config": { + "allowNewlines": true, + "required": false, + "hideFromForm": false, + "translatable": false + }, + "ui": { + "config": { + "readOnly": false + } + } + } + ], + "metadataGroups": [ + { + "label": "General", + "properties": [ + "title", + "description" + ], + "expanded": true + } + ] + } + ], + "mediaTypes": [ + { + "type": "mediaImage", + "handle": "image", + "info": { + "label": "Images", + "description": "" + }, + "asset": { + "translatable": true, + "replaceable": true + }, + "metadata": [ + { + "handle": "title", + "type": "li-text", + "config": { + "required": true, + "requiredErrorMessage": "Please provide a title", + "maxLength": 200, + "translatable": true, + "index": true, + "hideFromForm": false + }, + "ui": { + "config": { + "readOnly": false + } + } + } + ], + "editor": { + "dashboard": { + "displayFilters": [ + { + "filterName": "liDateTimeRange" + } + ], + "card": { + "name": "myImageCard" + } + }, + "managementDashboard": { + "displayFilters": [ + { + "filterName": "liDateTimeRange" + }, + { + "filterName": "category" + } + ] + } + } + } + ], + "designSettings": { + "assets": { + "css": [ + "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" + ] + }, + "mediaRendering": { + "backgroundImage": { + "defaultWidth": 1000 + }, + "srcSet": { + "defaultWidth": 1000, + "widths": [ + 1000, + 600, + 300 + ], + "sizes": [ + "100vw" + ] + }, + "video": { + "muted": true + } + }, + "componentGroups": [ + { + "name": "text", + "label": "Text", + "components": [ + "title", + "section-title", + "p" + ] + } + ], + "defaultComponents": { + "paragraph": "p", + "image": "image", + "video": "video-include" + }, + "fieldExtractor": [ + { + "identifier": "title", + "type": "text", + "matches": [ + "title.title" + ] + } + ], + "componentProperties": [ + { + "name": "depth", + "label": "Shadow", + "type": "option", + "value": "z-depth-2" + } + ], + "namedCrops": [ + { + "handle": "mobile", + "label": "Mobile", + "description": "this image will be shown on small screens", + "recommendedRatios": [ + "1:1", + "16:9" + ] + } + ] + }, + "components": [ + { + "name": "title", + "label": "Title", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_header_simple.svg", + "directives": [ + { + "type": "editable", + "name": "title", + "minLength": 1, + "maxLength": 150, + "recommendedMinLength": 20, + "recommendedMaxLength": 80, + "plainText": true + } + ], + "html": "

\n Title\n

" + }, + { + "name": "p", + "label": "Paragraph", + "iconUrl": "https://livingdocs-assets.s3.amazonaws.com/magazine-design/assets/images/icons-components/icon_text.svg", + "html": "

\n Paragraph\n

" + } + ], + "categories": [ + { + "id": "123abc", + "label": "Home", + "path": "/", + "metadata": { + "adId": "foo" + } + } + ], + "deliveries": [ + { + "handle": "web", + "label": "Website", + "isPrimary": true, + "icon": "book-open", + "url": { + "origin": "https://livingdocs.io", + "pathPattern": "/doc/:id" + } + } + ], + "notifications": { + "actionGroups": [ + { + "handle": "all", + "label": "All Events", + "description": "Comments, Tasks, Publish and delete", + "actions": [ + "task.change", + "document.publish", + "document.unpublish", + "document.copy", + "document.delete", + "document.transform", + "comment.add", + "comment.resolve" + ] + } + ], + "notifyTaskRequester": true, + "autoSubscribeOwner": { + "enabled": true, + "actionGroup": "all" + } + }, + "import": { + "allowedProjects": [ + { + "handle": "service-clone" + } + ] + }, + "export": { + "allowedProjects": [ + { + "handle": "service-clone" + } + ] + }, + "externalSystems": [ + { + "handle": "myExternalSystem", + "label": "My System", + "url": { + "origin": "https://example.com", + "pathPattern": "/{{metadata.myExternalSystemId}}" + }, + "icon": "track-light", + "isPrimary": false + } + ] + } diff --git a/content/reference/public-api/project/get_project_configuration.yaml b/content/reference/public-api/project/get_project_configuration.yaml new file mode 100644 index 000000000..d9da2f8c4 --- /dev/null +++ b/content/reference/public-api/project/get_project_configuration.yaml @@ -0,0 +1,91 @@ +title: Get Project Configuration ({{< deprecated-in "release-2023-03" >}}) + +deprecation: + since: release-2023-03 + note: Use `GET api/v1/projectConfig` instead. + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/project" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/project +deprecated: release-2023-03 +responses: + - code: "200" + body: | + { + "projectId": 1, + "name": "b5c5f804-7927-44e2-a3fd-f97bc6784dab", + "label": "Daily Planet", + "defaultChannelId": 1, + "channels": [ + { + "channelId": 1, + "channelHandle": "web", + "label": "Web", + "designName": "timeline", + "designVersion": "1.1.0", + "editMode": "default", + "contentTypeHandles": [ + "regular", + "page" + ], + "contentTypes": [ + { + "contentTypeHandle": "regular", + "documentType": "article", + "metadata": [ + { + "name": "title", + "plugin": "li-text" + }, + { + "name": "author", + "plugin": "li-text" + }, + { + "name": "teaserImage", + "plugin": "li-image" + }, + { + "name": "dependencies", + "plugin": "li-dependencies" + }, + { + "name": "tasks", + "plugin": "li-tasks" + } + ], + "renditionHandles": [ + "web", + "mobile" + ] + }, + { + "contentTypeHandle": "page", + "documentType": "page", + "metadata": [ + { + "name": "title", + "plugin": "li-text" + }, + { + "name": "dependencies", + "plugin": "li-dependencies" + }, + { + "name": "routing", + "plugin": "li-default-routing" + } + ], + "renditionHandles": [ + "web" + ] + } + ] + } + ] + } diff --git a/content/reference/public-api/publications/get_latest_publication.yaml b/content/reference/public-api/publications/get_latest_publication.yaml new file mode 100644 index 000000000..21a109ad6 --- /dev/null +++ b/content/reference/public-api/publications/get_latest_publication.yaml @@ -0,0 +1,192 @@ +title: Get Latest Publication +description: | + The endpoint provides an unresolved Publication with 4 possible top-level properties: + - systemdata + - metadata + - content + - renditions + + ##### Advantages + + - Be able to cache the response, because it only changes on a republish (does not contain resolved refs) + - Useful for a pull architecture + - (deprecated) Supports the Render Pipeline with it's Renditions + + ##### Related + + - [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) + - [Composition API]({{< ref "/reference/public-api/composition-api" >}}) + +useCases: | + - Load an unresolved Publication with the required information to render a document/page. + - Export the unresolved Publication to another system and get changes via [Publication Events]({{< ref "/reference/public-api/publications/publication-events" >}}) or [Webhooks]({{< ref "/reference/webhooks" >}}) + - (deprecated) Provides a Publication via a [Rendition]({{< ref "/reference/project-config/content-types#renditions" >}}) for a delivery in another format like `RSS`, `XML` + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/latestPublication" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/documents/:documentId/latestPublication +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?fields + type: string + required: false + notes: "Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions)." + - name: ?renditions + type: string + required: false + notes: | + A comma-separated list of rendition handles. + + Example: `?renditions=web,json` + + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `{"dateTime": new Date()}` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` +responses: + - code: "200" + body: | + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "regular", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-03-18T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "renditions": [ + { + "handle": "web", + "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" + }, + { + "handle": "mobile", + "content": { + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "design": { + "name": "timeline", + "version": "1.1.0" + } + } + }, + { + "handle": "app", + "error": { + "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" + } + } + ] + } diff --git a/content/reference/public-api/publications/get_latest_publication_beta.yaml b/content/reference/public-api/publications/get_latest_publication_beta.yaml new file mode 100644 index 000000000..31bb95ccb --- /dev/null +++ b/content/reference/public-api/publications/get_latest_publication_beta.yaml @@ -0,0 +1,198 @@ +title: Get Latest Publication +description: | + The endpoint provides an unresolved Publication with 5 possible top-level properties: + - systemdata + - metadata + - content + - renditions + - references + + Advantages: + - Be able to cache the response, because it only changes on a republish (does not contain resolved refs) + - Useful for a pull architecture + - (deprecated) Supports the Render Pipeline with it's Renditions + +useCases: | + - Load an unresolved Publication with the required information to render a document/page. + - Export the unresolved Publication to another system and get changes via [Publication Events]({{< ref "/reference/public-api/publications/publication-events" >}}) or [Webhooks]({{< ref "/reference/webhooks" >}}) + - (deprecated) Provides a Publication via a [Rendition]({{< ref "/reference/project-config/content-types#renditions" >}}) for a delivery in another format like `RSS`, `XML` + +scopes: public-api:read +beta: true +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/beta/documents/:documentId/latestPublication" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/beta/documents/:documentId/latestPublication +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?fields + type: string + required: false + notes: "Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions)." + - name: ?renditions + type: string + required: false + notes: | + A comma-separated list of rendition handles. + + Example: `?renditions=web,json` + + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `{"dateTime": new Date()}` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` +responses: + - code: "200" + name: OK + endpoint: /api/beta/documents/:documentId/latestPublication + body: | + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2023-03-18T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "renditions": [ + { + "handle": "web", + "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" + }, + { + "handle": "mobile", + "content": { + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "design": { + "name": "timeline", + "version": "1.1.0" + } + } + }, + { + "handle": "app", + "error": { + "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" + } + } + ], + "references": [ + { + "id": "YbzTpusGyJtF", + "type": "language-group", + "location": "metadata", + "propertyName": "language" + } + ] + } diff --git a/content/reference/public-api/publications/incoming_document_references.yaml b/content/reference/public-api/publications/incoming_document_references.yaml new file mode 100644 index 000000000..c18b5c91c --- /dev/null +++ b/content/reference/public-api/publications/incoming_document_references.yaml @@ -0,0 +1,74 @@ +title: Get Incoming Publication References for a Document +description: | + This endpoint returns all publications which link to this document (via content or metadata) + + The example below finds a reference to ID 1 when requesting for incomingDocumentReference with ID 2. + + {{< img src="./references.png" alt="Component Property" >}} + +useCases: | + - Find publications that link to this document for cache invalidation + + + >[!WARNING] + >- Eventual Consistency of Reference because of the usage of Elasticsearch + >- It is not supported to find publications in a [Document List]({{< ref "/reference/public-api/document-lists" >}}) put on another document. + + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/incomingDocumentReferences" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/documents/:documentId/incomingDocumentReferences +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?limit + type: integer + required: false + notes: "A limit for how much published documents to retrieve. Defaults to 100. Max. 100" + - name: ?offset + type: integer + required: false + notes: "An offset into the query. Useful when getting more than 100 results (pagination)" + +responses: +- code: "200" + body: | + [ + { + "id": 4, + "references": [ + { + "id": "1", + "type": "document", + "location": "include-directive", + "componentId": "doc-1euiflvoq0", + "serviceName": "editable-teaser", + "propertyName": "article", + "componentName": "teaser-include", + "directiveName": "teaser" + } + ] + }, + { + "id": 2, + "references": [ + { + "id": "1", + "type": "document", + "location": "include-directive", + "componentId": "doc-1eu6i7l880", + "serviceName": "editable-teaser", + "propertyName": "article", + "componentName": "teaser-include", + "directiveName": "teaser" + } + ] + } + ] diff --git a/content/reference/public-api/publications/incoming_media_references.yaml b/content/reference/public-api/publications/incoming_media_references.yaml new file mode 100644 index 000000000..a3ba0d4e4 --- /dev/null +++ b/content/reference/public-api/publications/incoming_media_references.yaml @@ -0,0 +1,45 @@ +title: Get Incoming Media References for a Document +description: | + This endpoint returns all Media Library Entries which link to this document (via metadata - li-document-reference) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/incomingMediaReferences" \ + -H "Authorization: Bearer $ACCESS_TOKEN" + +related: + - Foobar + +endpoint: + method: GET + path: /api/v1/documents/:documentId/incomingMediaReferences +parameters: + - name: :documentId + type: integer + required: true + notes: "" + - name: ?limit + type: integer + required: false + notes: "A limit for how much published documents to retrieve. Defaults to 100. Max. 100" + - name: ?offset + type: integer + required: false + notes: "An offset into the query. Useful when getting more than 100 results (pagination)" +responses: +- code: "200" + body: | + [ + { + "id": "98sXCahM5PEk", + "references": [ + { + "id": "3", + "type": "document", + "location": "metadata", + "propertyName": "documentLink" + } + ] + } + ] diff --git a/content/reference/public-api/publications/latest-publication-beta.md b/content/reference/public-api/publications/latest-publication-beta.md index 16d7324f5..d9a251ac9 100644 --- a/content/reference/public-api/publications/latest-publication-beta.md +++ b/content/reference/public-api/publications/latest-publication-beta.md @@ -8,193 +8,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Latest Publication" - scopes="public-api:read" - beta=true ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/beta/documents/:documentId/latestPublication" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/beta/documents/:documentId/latestPublication -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?fields|string||Filters which (comma separated) properties are included in the response. Defaults to 'systemdata,metadata,content' (no renditions).| -|?renditions|string||A comma-separated list of rendition handles. Example: `?renditions=web,json`| -|?ignoreComponentConditions|boolean||Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string||JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- -The endpoint provides an unresolved Publication with 5 possible top-level properties: -- systemdata -- metadata -- content -- renditions -- references - -##### Advantages - -- Be able to cache the response, because it only changes on a republish (does not contain resolved refs) -- Useful for a pull architecture -- (deprecated) Supports the Render Pipeline with it's Renditions - - -##### Use Cases - -- Load an unresolved Publication with the required information to render a document/page. -- Export the unresolved Publication to another system and get changes via [Publication Events]({{< ref "/reference/public-api/publications/publication-events" >}}) or [Webhooks]({{< ref "/reference/webhooks" >}}) -- (deprecated) Provides a Publication via a [Rendition]({{< ref "/reference/project-config/content-types#renditions" >}}) for a delivery in another format like `RSS`, `XML` - -##### Related - -- [Latest Publication API]({{< ref "/reference/public-api/publications/latest-publication" >}}) -- [Composition API]({{< ref "/reference/public-api/composition-api" >}}) - ---response-- -200 ---- ---- -```js -{ - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-18T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "renditions": [ - { - "handle": "web", - "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" - }, - { - "handle": "mobile", - "content": { - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "design": { - "name": "timeline", - "version": "1.1.0" - } - } - }, - { - "handle": "app", - "error": { - "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" - } - } - ], - "references": [ - { - "id": "YbzTpusGyJtF", - "type": "language-group", - "location": "metadata", - "propertyName": "language" - } - ] -} -``` - -{{< /api-example >}} +{{< api-example-resource file="get_latest_publication_beta.yaml" >}} diff --git a/content/reference/public-api/publications/latest-publication.md b/content/reference/public-api/publications/latest-publication.md index 24398fc3f..e32f813e9 100644 --- a/content/reference/public-api/publications/latest-publication.md +++ b/content/reference/public-api/publications/latest-publication.md @@ -1,5 +1,6 @@ --- -title: Latest Publication  +title: Latest Publication +identifier: Latest Publication weight: 1 renderTOC: false menus: @@ -7,184 +8,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Latest Publication" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/latestPublication" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/documents/:documentId/latestPublication -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?fields|string||Filters which (comma separated) properties are included in the response. Defaults to 'systemdata,metadata,content' (no renditions).| -|?renditions|string||A comma-separated list of rendition handles. Example: `?renditions=web,json`| -|?ignoreComponentConditions|boolean||Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string||JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- - -The endpoint provides an unresolved Publication with 4 possible top-level properties: -- systemdata -- metadata -- content -- renditions - -##### Advantages - -- Be able to cache the response, because it only changes on a republish (does not contain resolved refs) -- Useful for a pull architecture -- (deprecated) Supports the Render Pipeline with it's Renditions - - -##### Use Cases - -- Load an unresolved Publication with the required information to render a document/page. -- Export the unresolved Publication to another system and get changes via [Publication Events]({{< ref "/reference/public-api/publications/publication-events" >}}) or [Webhooks]({{< ref "/reference/webhooks" >}}) -- (deprecated) Provides a Publication via a [Rendition]({{< ref "/reference/project-config/content-types#renditions" >}}) for a delivery in another format like `RSS`, `XML` - -##### Related - -- [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) -- [Composition API]({{< ref "/reference/public-api/composition-api" >}}) - ---response-- -200 ---- ---- -```js -{ - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "regular", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2023-03-18T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "renditions": [ - { - "handle": "web", - "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" - }, - { - "handle": "mobile", - "content": { - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "design": { - "name": "timeline", - "version": "1.1.0" - } - } - }, - { - "handle": "app", - "error": { - "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" - } - } - ] -} -``` - -{{< /api-example >}} +{{< api-example-resource file="get_latest_publication.yaml" >}} diff --git a/content/reference/public-api/publications/latest-publications-beta.md b/content/reference/public-api/publications/latest-publications-beta.md index f6459a46c..ffa597b9f 100644 --- a/content/reference/public-api/publications/latest-publications-beta.md +++ b/content/reference/public-api/publications/latest-publications-beta.md @@ -8,198 +8,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Latest Publications" - scopes="public-api:read" - beta=true ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/beta/documents/latestPublications" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/beta/documents/latestPublications -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|?fields|string|Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions).| -|?reverse|boolean|Order publications in ascending order instead of the default descending order. This is useful if you want to paginate using a time based filter.| -|?homepage|boolean|Return only the document labeled as homepage in the current project.| -|?contentTypes|string|Comma separated list of content types to use as filter.| -|?documentTypes|string|Comma separated list of document types to use as filter.
Can be one of `article`, `page`, `data-record`.| -|?id.gte|string|Filter by document id range.
Supported filters: `id.gte`, `id.gt`, `id.lte`, `id.lt`.

The id range filter is useful if you want to export a lot of documents. You can do many requests in parallel against the api, where you filter by the specific ranges.

This query is much more flexible than an offset-based filter and works with millions of documents.
**Request 1:** `?id.gt=0&id.lte=100`
**Request 2:** `?id.gt=100&id.lte=200`
**Request 3:** `?id.gt=200&id.lte=300`| -|?id|string|Filter by one or multiple document ids.
**Example 1:** `?id=12`
**Example 2:** `?id=100,120,123`| -|?publishedAt.gte|string|Filter by publish date range.
Supported filters: `?publishedAt.gte`, `publishedAt.gt`, `publishedAt.lte`, `publishedAt.lt`.

Example: To retrieve all publications since a specific timestamp, use `?reverse&publishedAt.gte=2021-05-01T00:00:00.000Z`| -|?ignoreComponentConditions|boolean|Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string|JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| -|?limit|integer|A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer|An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000. Prefer range based filters like id.get or publishedAt.gte.| - ---description-- - -The endpoint provides an unresolved Publication with 4 possible top-level properties: -- systemdata -- metadata -- content -- references - -##### Use Cases - -- Bulk export of data, e.g. a specific `Content Type` - ---response-- -200 ---- ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2022-10-30T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "references": [ - { - "id": "YbzTpusGyJtF", - "type": "language-group", - "location": "metadata", - "propertyName": "language" - } - ] - }, - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 2, - "contentType": "article", - "documentType": "article", - "publicationId": 5, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2022-10-30T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "another title", - "description": "some other lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "references": [ - { - "id": "YbzTpusGyJtF", - "type": "language-group", - "location": "metadata", - "propertyName": "language" - } - ] - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="latest_publications_beta.yaml" >}} diff --git a/content/reference/public-api/publications/latest-publications.md b/content/reference/public-api/publications/latest-publications.md index 396aaede7..25129089f 100644 --- a/content/reference/public-api/publications/latest-publications.md +++ b/content/reference/public-api/publications/latest-publications.md @@ -1,5 +1,5 @@ --- -title: Latest Publications  +title: Latest Publications weight: 3 renderTOC: false menus: @@ -7,180 +7,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Latest Publications" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/documents/latestPublications" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/documents/latestPublications -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|?fields|string|Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions).| -|?reverse|boolean|Order publications in ascending order instead of the default descending order (the property used for sorting is `lastPublicationDate`). This is useful if you want to paginate using a time based filter.| -|?homepage|boolean|Return only the document labeled as homepage in the current project.| -|?contentTypes|string|Comma separated list of content types to use as filter.| -|?documentTypes|string|Comma separated list of document types to use as filter.
Can be one of `article`, `page`, `data-record`.| -|?id.gte|string|Filter by document id range.

Supported filters: `id.gte`, `id.gt`, `id.lte`, `id.lt`.

The id range filter is useful if you want to export a lot of documents. You can do many requests in parallel against the api, where you filter by the specific ranges.

This query is much more flexible than an offset-based filter and works with millions of documents.

Request 1: `?id.gt=0&id.lte=100`
Request 2: `?id.gt=100&id.lte=200`
Request 3: `?id.gt=200&id.lte=300`| -|?id|string|Filter by one or multiple document ids.
**Example 1:** `?id=12`
**Example 2:** `?id=100,120,123`| -|?publishedAt.gte|string|Filter by publish date range.
Supported filters: `publishedAt.gte`, `publishedAt.gt`, `publishedAt.lte`, `publishedAt.lt` (the filtered property is `lastPublicationDate`).

Example: To retrieve all publications since a specific timestamp, use `?reverse&publishedAt.gte=2021-05-01T00:00:00.000Z`| -|?ignoreComponentConditions|boolean|Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string|JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| -|?limit|integer|A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer|An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000. Prefer range based filters like id.get or publishedAt.gte.| - ---description-- - -The endpoint provides an unresolved Publication with 3 possible top-level properties: -- systemdata -- metadata -- content - -##### Use Cases - -- Bulk export of data, e.g. a specific `Content Type` - ---response-- -200 ---- ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "publicationId": 1, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2022-10-30T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "a title", - "description": "some lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - }, - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 2, - "contentType": "article", - "documentType": "article", - "publicationId": 5, - "firstPublicationDate": "2022-03-16T14:08:11:000Z", - "significantPublicationDate": "2022-10-26T07:25:00.000Z", - "visiblePublicationDate": "2022-10-27T06:00:00.000Z", - "lastPublicationDate": "2022-10-30T16:32:04.170Z", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "another title", - "description": "some other lead", - "dependencies": {} - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="latest_publications.yaml" >}} diff --git a/content/reference/public-api/publications/latest_publications.yaml b/content/reference/public-api/publications/latest_publications.yaml new file mode 100644 index 000000000..566f3afc2 --- /dev/null +++ b/content/reference/public-api/publications/latest_publications.yaml @@ -0,0 +1,231 @@ +title: Get Latest Publications +description: | + The endpoint provides an unresolved Publication with 3 possible top-level properties: + - systemdata + - metadata + - content + +useCases: | + - Bulk export of data, e.g. a specific `Content Type` + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/latestPublications" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/documents/latestPublications +parameters: + - name: ?fields + type: string + required: false + notes: "Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions)" + - name: ?reverse + type: boolean + required: false + notes: "Order publications in ascending order instead of the default descending order (the property used for sorting is `lastPublicationDate`). This is useful if you want to paginate using a time based filter" + - name: ?homepage + type: boolean + required: false + notes: "Return only the document labeled as homepage in the current project" + - name: ?contentTypes + type: string + required: false + notes: "Comma separated list of content types to use as filter" + - name: ?documentTypes + type: string + required: false + notes: | + Comma separated list of document types to use as filter. + + Can be one of `article`, `page`, `data-record` + - name: ?id.gte + type: string + required: false + notes: | + Filter by document id range. + + Supported filters: `id.gte`, `id.gt`, `id.lte`, `id.lt`. + + The id range filter is useful if you want to export a lot of documents. + You can do many requests in parallel against the api, where you filter by the specific ranges. + + This query is much more flexible than an offset-based filter and works with millions of documents. + + Request 1: `?id.gt=0&id.lte=100` + Request 2: `?id.gt=100&id.lte=200` + Request 3: `?id.gt=200&id.lte=300` + - name: ?id + type: string + required: false + notes: | + Filter by one or multiple document ids. + + **Example 1**: `?id=12` + **Example 2**: `?id=100,120,123` + - name: ?publishedAt.gte + type: string + required: false + notes: | + Filter by publish date range. + + Supported filters: `publishedAt.gte`, `publishedAt.gt`, `publishedAt.lte`, `publishedAt.lt` (the filtered property is `lastPublicationDate`). + + Example: To retrieve all publications since a specific timestamp, use `?reverse&publishedAt.gte=2021-05-01T00:00:00.000Z`" + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `{"dateTime": new Date()}` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + - name: ?limit + type: integer + required: false + notes: A limit for how much published documents to retrieve. Defaults to 100. Max. 100 + - name: ?offset + type: integer + required: false + notes: An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000. Prefer range based filters like id.get or publishedAt.gte + +responses: + - code: "200" + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2022-10-30T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + }, + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 2, + "contentType": "article", + "documentType": "article", + "publicationId": 5, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2022-10-30T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "another title", + "description": "some other lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + } + ] diff --git a/content/reference/public-api/publications/latest_publications_beta.yaml b/content/reference/public-api/publications/latest_publications_beta.yaml new file mode 100644 index 000000000..7b3abc70c --- /dev/null +++ b/content/reference/public-api/publications/latest_publications_beta.yaml @@ -0,0 +1,249 @@ +title: Get Latest Publications +description: | + The endpoint provides an unresolved Publication with 4 possible top-level properties: + - systemdata + - metadata + - content + - references + +beta: true +useCases: | + - Bulk export of data, e.g. a specific `Content Type` + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/latestPublications" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/documents/latestPublications +parameters: + - name: ?fields + type: string + required: false + notes: "Filters which (comma separated) properties are included in the response. Defaults to `systemdata,metadata,content` (no renditions)" + - name: ?reverse + type: boolean + required: false + notes: "Order publications in ascending order instead of the default descending order (the property used for sorting is `lastPublicationDate`). This is useful if you want to paginate using a time based filter" + - name: ?homepage + type: boolean + required: false + notes: "Return only the document labeled as homepage in the current project" + - name: ?contentTypes + type: string + required: false + notes: "Comma separated list of content types to use as filter" + - name: ?documentTypes + type: string + required: false + notes: | + Comma separated list of document types to use as filter. + + Can be one of `article`, `page`, `data-record` + - name: ?id.gte + type: string + required: false + notes: | + Filter by document id range. + + Supported filters: `id.gte`, `id.gt`, `id.lte`, `id.lt`. + + The id range filter is useful if you want to export a lot of documents. + You can do many requests in parallel against the api, where you filter by the specific ranges. + + This query is much more flexible than an offset-based filter and works with millions of documents. + + Request 1: `?id.gt=0&id.lte=100` + Request 2: `?id.gt=100&id.lte=200` + Request 3: `?id.gt=200&id.lte=300` + - name: ?id + type: string + required: false + notes: | + Filter by one or multiple document ids. + + **Example 1**: `?id=12` + **Example 2**: `?id=100,120,123` + - name: ?publishedAt.gte + type: string + required: false + notes: | + Filter by publish date range. + + Supported filters: `publishedAt.gte`, `publishedAt.gt`, `publishedAt.lte`, `publishedAt.lt` (the filtered property is `lastPublicationDate`). + + Example: To retrieve all publications since a specific timestamp, use `?reverse&publishedAt.gte=2021-05-01T00:00:00.000Z`" + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in \"release-2024-03\" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `{"dateTime": new Date()}` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + - name: ?limit + type: integer + required: false + notes: A limit for how much published documents to retrieve. Defaults to 100. Max. 100 + - name: ?offset + type: integer + required: false + notes: An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000. Prefer range based filters like id.get or publishedAt.gte + +responses: + - code: "200" + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "publicationId": 1, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2022-10-30T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "a title", + "description": "some lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "references": [ + { + "id": "YbzTpusGyJtF", + "type": "language-group", + "location": "metadata", + "propertyName": "language" + } + ] + }, + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 2, + "contentType": "article", + "documentType": "article", + "publicationId": 5, + "firstPublicationDate": "2022-03-16T14:08:11:000Z", + "significantPublicationDate": "2022-10-26T07:25:00.000Z", + "visiblePublicationDate": "2022-10-27T06:00:00.000Z", + "lastPublicationDate": "2022-10-30T16:32:04.170Z", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "another title", + "description": "some other lead", + "dependencies": {} + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "references": [ + { + "id": "YbzTpusGyJtF", + "type": "language-group", + "location": "metadata", + "propertyName": "language" + } + ] + } + ] diff --git a/content/reference/public-api/publications/publication-events.md b/content/reference/public-api/publications/publication-events.md index 17933825f..9b1100420 100644 --- a/content/reference/public-api/publications/publication-events.md +++ b/content/reference/public-api/publications/publication-events.md @@ -7,129 +7,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Publication Events" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/publicationEvents" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/publicationEvents -``` -``` -GET api/v1/publicationEvents/:channelHandle -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|:channelHandle|string|The handle of the channel for which you want to get the events.| -|?limit|integer|Number of events to return. Default: 100. Highest limit: 1000.| -|?reverse|boolean|Returns the events in reverse order, starting at the biggest id.| -|?contentTypes|string|Comma separated list of content types to use as filter.| -|?documentTypes|string|Comma separated list of document types to use as filter.
Can be one of `article`, `page`, `data-record`.| -|?after|integer|Deprecated: Please use `id.gte` instead.
Return matching events after this event id.| -|?id.gte|string|Filter by event id range.
**Supported filters:** `id.gte`, `id.gt`, `id.lte`, `id.lt`.
**Example:** To retrieve all events since you've fetched the last entry, use `?limit=1000&id.gt=40000`| -|?createdAt.gte|string|Filter by event date range.
**Supported filters:** `createdAt.gte`, `createdAt.gt`, `createdAt.lte`, `createdAt.lt`.
**Example:** To retrieve all events since a specific timestamp, use `?limit=1000&createdAt.gte=2021-05-01T00:00:00.000Z`| - ---description-- - -This endpoint returns publication events (`publish`, `unpublish`, `update`) for a project. - -##### Use Cases - -- Reliably fetch documents publication state changes to sync with another system -- Cache invalidation management - -##### Related - -- [Webhooks]({{< ref "/reference/webhooks" >}}) - ---response-- -200 ---- -api/v1/publicationEvents ---- -```js -[ - { - "id": 910, - "createdAt": "2016-12-27T09:19:00.928Z", - "projectId": 30, - "channelId": 53, - "documentId": 7892, - "documentType": "article", - "eventType": "publish", - "publicationId": 1066 - }, - { - "id": 988, - "createdAt": "2016-12-27T09:32:10.898Z", - "projectId": 30, - "channelId": 53, - "documentId": 7892, - "documentType": "article", - "eventType": "unpublish", - "publicationId": 1100 - }, - { - "id": 990, - "createdAt": "2016-12-27T09:33:05.010Z", - "projectId": 30, - "channelId": 53, - "documentId": 8005, - "documentType": "article", - "eventType": "publish", - "publicationId": 1131 - }, - { - "id": 1011, - "createdAt": "2016-12-27T09:33:31.517Z", - "projectId": 30, - "channelId": 53, - "documentId": 7892, - "documentType": "article", - "eventType": "update", - "publicationId": 1394 - } -] -``` ------ -200 ---- -api/v1/publicationEvents?reverse&limit=2 ---- -```js -[ - { - "id": 1011, - "createdAt": "2016-12-27T09:33:31.517Z", - "projectId": 30, - "channelId": 53, - "documentId": 7892, - "documentType": "article", - "eventType": "update", - "publicationId": 1394 - }, - { - "id": 990, - "createdAt": "2016-12-27T09:33:05.010Z", - "projectId": 30, - "channelId": 53, - "documentId": 8005, - "documentType": "article", - "eventType": "publish", - "publicationId": 1131 - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="publication_events.yaml" >}} diff --git a/content/reference/public-api/publications/publication_events.yaml b/content/reference/public-api/publications/publication_events.yaml new file mode 100644 index 000000000..c3325e627 --- /dev/null +++ b/content/reference/public-api/publications/publication_events.yaml @@ -0,0 +1,136 @@ +title: Get Publication Events +description: | + This endpoint returns publication events (`publish`, `unpublish`, `update`) for a project. + + #### Related + - [Webhooks]({{< ref "/reference/webhooks" >}}) + +useCases: | + - Reliably fetch documents publication state changes to sync with another system + - Cache invalidation management + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/publicationEvents" \ + -H "Authorization: Bearer $ACCESS_TOKEN" + +endpoint: + method: GET + path: /api/v1/publicationEvents + # TODO: add /api/v1/publicationEvents/:channelHandle +parameters: + - name: :channelHandle + type: string + required: false + notes: "The handle of the channel for which you want to get the events" + - name: ?limit + type: integer + required: false + notes: "Number of events to return. Default: 100. Highest limit: 1000" + - name: ?reverse + type: boolean + required: false + notes: "Returns the events in reverse order, starting at the biggest id" + - name: ?contentTypes + type: string + required: false + notes: "Comma separated list of content types to use as filter" + - name: ?documentTypes + type: string + required: false + notes: "Comma separated list of document types to use as filter. Can be one of `article`, `page`, `data-record`" + - name: ?after + type: integer + required: false + notes: "Deprecated: Please use `id.gte` instead. Return matching events after this event id" + - name: ?id.gte + type: string + required: false + notes: | + Filter by event id range. + + **Supported filters:** `id.gte`, `id.gt`, `id.lte`, `id.lt`. + + **Example:** To retrieve all events since you've fetched the last entry, use `?limit=1000&id.gt=40000`" + - name: ?createdAt.gte + type: string + required: false + notes: | + Filter by event date range. + + **Supported filters:** `createdAt.gte`, `createdAt.gt`, `createdAt.lte`, `createdAt.lt`. + + **Example:** To retrieve all events since a specific timestamp, use `?limit=1000&createdAt.gte=2021-05-01T00:00:00.000Z`" + +responses: +- code: "200" + endpoint: /api/v1/publicationEvents + body: | + [ + { + "id": 910, + "createdAt": "2016-12-27T09:19:00.928Z", + "projectId": 30, + "channelId": 53, + "documentId": 7892, + "documentType": "article", + "eventType": "publish", + "publicationId": 1066 + }, + { + "id": 988, + "createdAt": "2016-12-27T09:32:10.898Z", + "projectId": 30, + "channelId": 53, + "documentId": 7892, + "documentType": "article", + "eventType": "unpublish", + "publicationId": 1100 + }, + { + "id": 990, + "createdAt": "2016-12-27T09:33:05.010Z", + "projectId": 30, + "channelId": 53, + "documentId": 8005, + "documentType": "article", + "eventType": "publish", + "publicationId": 1131 + }, + { + "id": 1011, + "createdAt": "2016-12-27T09:33:31.517Z", + "projectId": 30, + "channelId": 53, + "documentId": 7892, + "documentType": "article", + "eventType": "update", + "publicationId": 1394 + } + ] +- code: "200" + endpoint: /api/v1/publicationEvents?reverse&limit=2 + body: | + [ + { + "id": 1011, + "createdAt": "2016-12-27T09:33:31.517Z", + "projectId": 30, + "channelId": 53, + "documentId": 7892, + "documentType": "article", + "eventType": "update", + "publicationId": 1394 + }, + { + "id": 990, + "createdAt": "2016-12-27T09:33:05.010Z", + "projectId": 30, + "channelId": 53, + "documentId": 8005, + "documentType": "article", + "eventType": "publish", + "publicationId": 1131 + } + ] diff --git a/content/reference/public-api/publications/publication_renditions.yaml b/content/reference/public-api/publications/publication_renditions.yaml new file mode 100644 index 000000000..0eececa78 --- /dev/null +++ b/content/reference/public-api/publications/publication_renditions.yaml @@ -0,0 +1,105 @@ +title: Get Specific Renditions for a Publication +description: | + With the Renditions Endpoint you can load different output formats of your publication like `RSS`, `XML`, `HTML` etc. Attention: A rendition is only available if the output format is configured in the [Content Type]({{< ref "/reference/project-config/content-types#renditions" >}}) configuration. + + #### Related + - [Latest Publication API]({{< ref "/reference/public-api/publications/latest-publication" >}}) + - [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) + - [Composition API]({{< ref "/reference/public-api/composition-api" >}}) + +useCases: | + - Provides a Publication for a delivery in another format like `RSS`, `XML` (so called `Rendition`) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles +parameters: + - name: :renditionHandles + type: string + required: true + notes: "A comma-separated list of renditions handles, e.g. \"web,name\"" + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in "release-2024-03" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in "release-2024-03" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `dateTime: new Date()` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + +responses: +- code: "200" + body: | + [ + { + "handle": "web", + "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" + }, + { + "handle": "mobile", + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "a title", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ], + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + { + "handle": "app", + "error": { + "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" + } + } + ] diff --git a/content/reference/public-api/publications/references.md b/content/reference/public-api/publications/references.md index c7ab53eb2..e987d652a 100644 --- a/content/reference/public-api/publications/references.md +++ b/content/reference/public-api/publications/references.md @@ -7,141 +7,6 @@ menus: parent: Publications --- -{{< api-example - title="Get Incoming Publication References for a Document" - scopes="public-api:read" ->}} +{{< api-example-resource file="incoming_document_references.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/incomingDocumentReferences" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/documents/:documentId/incomingDocumentReferences -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?limit|integer||A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer||An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- - -This endpoint returns all publications which link to this document (via content or metadata) - -The example below finds a reference to ID 1 when requesting for incomingDocumentReference with ID 2. - -{{< img src="./references.png" alt="Component Property" >}} - - -##### Use Cases - -- Find publications that link to this document for cache invalidation - -##### Notes - -- Eventual Consistency of Reference because of the usage of Elasticsearch - - -##### Not Supported - -Find publications in a [Document List]({{< ref "/reference/public-api/document-lists" >}}) put on another document. - ---response-- -200 ---- ---- -```js -[ - { - "id": 4, - "references": [ - { - "id": "1", - "type": "document", - "location": "include-directive", - "componentId": "doc-1euiflvoq0", - "serviceName": "editable-teaser", - "propertyName": "article", - "componentName": "teaser-include", - "directiveName": "teaser" - } - ] - }, - { - "id": 2, - "references": [ - { - "id": "1", - "type": "document", - "location": "include-directive", - "componentId": "doc-1eu6i7l880", - "serviceName": "editable-teaser", - "propertyName": "article", - "componentName": "teaser-include", - "directiveName": "teaser" - } - ] - } -] -``` - -{{< /api-example >}} - -{{< api-example - title="Get Incoming Media References for a Document" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/incomingMediaReferences" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/documents/:documentId/incomingMediaReferences -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:documentId|integer|x|| -|?limit|integer||A limit for how much published documents to retrieve. Defaults to 100. Max. 100.| -|?offset|integer||An offset into the query. Useful when getting more than 100 results (pagination).| - ---description-- - -This endpoint returns all Media Library Entries which link to this document (via metadata - li-document-reference) - ---response-- -200 ---- ---- -```js -[ - { - "id": "98sXCahM5PEk", - "references": [ - { - "id": "3", - "type": "document", - "location": "metadata", - "propertyName": "documentLink" - } - ] - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="incoming_media_references.yaml" >}} diff --git a/content/reference/public-api/publications/renditions.md b/content/reference/public-api/publications/renditions.md index 0217a97ce..6aa6b99ed 100644 --- a/content/reference/public-api/publications/renditions.md +++ b/content/reference/public-api/publications/renditions.md @@ -7,109 +7,4 @@ menus: parent: Publications --- -{{< api-example - title="Get Specific Renditions for a Publication" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/documents/:documentId/latestPublication/renditions/:renditionHandles -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:renditionHandles|string|x|A comma-separated list of renditions handles, e.g. "web,name".| -|?ignoreComponentConditions|boolean||Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string||JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- - -With the Renditions Endpoint you can load different output formats of your publication like `RSS`, `XML`, `HTML` etc. Attention: A rendition is only available if the output format is configured in the [Content Type]({{< ref "/reference/project-config/content-types#renditions" >}}) configuration. - -##### Use Cases - -- Provides a Publication for a delivery in another format like `RSS`, `XML` (so called `Rendition`) - -##### Related - - -- [Latest Publication API]({{< ref "/reference/public-api/publications/latest-publication" >}}) -- [Latest Publication API Beta]({{< ref "/reference/public-api/publications/latest-publication-beta" >}}) -- [Composition API]({{< ref "/reference/public-api/composition-api" >}}) - - ---response-- -200 ---- ---- -```js -[ - { - "handle": "web", - "content": "
\n

a title

\n

some lead

\n
\n
\n \n
my caption
\n
\n

first paragraph

\n

second

\n

and third one. :)

" - }, - { - "handle": "mobile", - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "a title", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ], - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - { - "handle": "app", - "error": { - "message": "Processing of Channel 'app' for document '1' failed. Detailed error message…" - } - } -] -``` - -{{< /api-example >}} +{{< api-example-resource file="publication_renditions.yaml" >}} diff --git a/content/reference/public-api/publications/search.md b/content/reference/public-api/publications/search.md index 47796aca7..cb4088d8f 100644 --- a/content/reference/public-api/publications/search.md +++ b/content/reference/public-api/publications/search.md @@ -6,281 +6,8 @@ menus: parent: Publications --- -{{< api-example - title="Search Publications" - scopes="public-api:read" ->}} +{{< api-example-resource file="search_publications.yaml" >}} ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/publications/search" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/publications/search -``` - ---parameters-- -|Name|Type|Notes| -|-|-|-| -|?search|string|Search term to perform a full-text search with. For exact word matches use ", e.g. 'search="Ukulele"'| -|?contentTypes|string|Comma separated list of content-types for which documents should be found. Content types are concatenated with OR. Example: 'regular,author'| -|?categories|string|Comma separated list of category ids for which documents should be found. Categories are concatenated with OR. Example: 'sport,fashion'| -|?languages|string|Comma separated list of languages for which documents should be found. Languages are concatenated with OR. Example: 'en,de'| -|?languageGroupId|string|A GroupId used to fetch all translations of a document Using the ?languages param a document in a specific language can be fetched. Example: '?languageGroupId=47?language=de'| -|?filters|string|A JSON string which follows the [search filters query DSL]({{< ref "#search-filters" >}}).| -|?sort|string|Comma separated list of sort properties. Any of the [Sort Fields]({{< ref "#sort-fields" >}}) can be used.
The sort order can be reversed by prefixing the property with a '-'. -|?fields|string|Comma separated list of properties to include in the response. Defaults to 'systemdata,metadata,content' (no renditions). Use 'id' if you only want to retrieve the ids of the published documents. Useful (and faster) if you are fully synchronizing your frontend with the publication events.| -|?limit|integer|A limit for how much published documents to retrieve. Defaults to 10. Max. 100.| -|?offset|integer|An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000.| -|?ignoreComponentConditions|boolean|Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks.
{{< added-in "release-2024-03" >}}
Default: `false`| -|?componentConditions|string|JSON stringified object which contains the component conditions you would like to apply.
{{< added-in "release-2024-03" >}}
Default: `dateTime: new Date()`
Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}`| - ---description-- - -This endpoint allows filtering for published documents. - -##### Use Cases - -- Automatic teaser lists like topic pages (filtered by Metadata properties) -- [Ticker Tool]({{< ref "/operations/releases/release-2023-09#ticker-tool" >}}) - -##### Notes - -- Even when it's possible to make a full-text search to this endpoint, it's not thought to be used by a frontend search (because of performance reasons) - ---response-- -200 ---- -api/v1/publications/search?search=Obama ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "Obama re-elected", - "description": "some lead", - "dependencies": {}, - "testDependency": "li-test-dependency.onUpdate is correct" - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "Obama re-elected", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - } -] -``` ------ -200 ---- -api/v1/publications/search?categories=sport,fashion&languages=en ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "article", - "documentType": "article", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "Bayern to win Champions League", - "description": "some lead", - "category": { - "id": "sport" - }, - "language": { - "locale": "en" - }, - "dependencies": {}, - "testDependency": "li-test-dependency.onUpdate is correct" - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "Bayern to win Champions League", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - } -] -``` ------ -200 ---- -api/v1/publications/search?contentTypes=regular,gallery&limit=10&offset=10 ---- -```js -[ - { - "systemdata": { - "projectId": 1, - "channelId": 1, - "documentId": 1, - "contentType": "regular", - "documentType": "article", - "design": { - "name": "timeline", - "version": "1.1.0" - } - }, - "metadata": { - "title": "Bayern to win Champions League", - "description": "some lead", - "category": { - "id": "sport" - }, - "language": { - "locale": "en" - }, - "dependencies": {}, - "testDependency": "li-test-dependency.onUpdate is correct" - }, - "content": [ - { - "id": "doc-1b8i1ksh10", - "component": "head", - "identifier": "timeline.head", - "content": { - "title": "Bayern to win Champions League", - "text": "some lead" - } - }, - { - "id": "doc-1b8i1ksh20", - "component": "normal", - "identifier": "timeline.normal", - "content": { - "caption": "my caption" - }, - "styles": { - "position": "left" - } - }, - { - "id": "doc-1b8i1ksh30", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "first paragraph" - } - }, - { - "id": "doc-1b8i1me1d0", - "component": "p", - "identifier": "timeline.p", - "content": { - "text": "second paragraph" - } - } - ] - } -] -``` ------ -200 ---- -api/v1/publications/search?contentTypes=article&limit=999&fields=id ---- -```js -[ - { - "documentId": 1, - "projectId": 1 - }, - { - "documentId": 2, - "projectId": 1 - } -] -``` -{{< /api-example >}} ## Search Filters diff --git a/content/reference/public-api/publications/search_publications.yaml b/content/reference/public-api/publications/search_publications.yaml new file mode 100644 index 000000000..6da05f9a8 --- /dev/null +++ b/content/reference/public-api/publications/search_publications.yaml @@ -0,0 +1,300 @@ +title: Search Publications +description: | + This endpoint allows filtering for published documents. + +useCases: | + - Automatic teaser lists like topic pages (filtered by Metadata properties) + - [Ticker Tool]({{< ref "/operations/releases/release-2023-09#ticker-tool" >}}) + + >[!WARNING] + > Even when it’s possible to make a full-text search to this endpoint, it's not thought to be used by a frontend search (because of performance reasons) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/publications/search" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/publications/search +parameters: + - name: ?search + type: string + required: false + notes: "Search term to perform a full-text search with. For exact word matches use \", e.g. 'search=\"Ukulele\"'" + - name: ?contentTypes + type: string + required: false + notes: "Comma separated list of content-types for which documents should be found. Content types are concatenated with OR. Example: 'regular,author'" + - name: ?categories + type: string + required: false + notes: "Comma separated list of category ids for which documents should be found. Categories are concatenated with OR. Example: 'sport,fashion'" + - name: ?languages + type: string + required: false + notes: "Comma separated list of languages for which documents should be found. Languages are concatenated with OR. Example: 'en,de'" + - name: ?languageGroupId + type: string + required: false + notes: | + A GroupId used to fetch all translations of a document. + Using the `?languages` param a document in a specific language can be fetched. + Example: `?languageGroupId=47&language=de` + - name: ?filters + type: string + required: false + notes: "A JSON string which follows the [search filters query DSL]({{< ref \"#search-filters\" >}})" + - name: ?sort + type: string + required: false + notes: | + Comma separated list of sort properties. Any of the [Sort Fields]({{< ref \"#sort-fields\" >}}) can be used. The sort order can be reversed by prefixing the property with a `-` + - name: ?fields + type: string + required: false + notes: | + Comma separated list of properties to include in the response. Defaults to `systemdata,metadata,content` (no renditions). Use `id` if you only want to retrieve the ids of the published documents. Useful (and faster) if you are fully synchronizing your frontend with the publication events + - name: ?limit + type: integer + required: false + notes: "A limit for how much published documents to retrieve. Defaults to 10. Max. 100" + - name: ?offset + type: integer + required: false + notes: "An offset into the query. Useful when getting more than 100 results (pagination). Max. 10000" + - name: ?ignoreComponentConditions + type: boolean + required: false + notes: | + {{< added-in "release-2024-03" >}} + + Provides a way to opt out of component filtering and return all content regardless of whether each component passes the conditional checks. + + Default: `false` + - name: ?componentConditions + type: string + required: false + notes: | + {{< added-in "release-2024-03" >}} + + JSON stringified object which contains the component conditions you would like to apply. + + Default: `dateTime: new Date()` + Example: `?componentConditions={"dateTime":"2024-02-14T17:25:10.391Z"}` + +responses: +- code: "200" + endpoint: /api/v1/publications/search?search=Obama + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "Obama re-elected", + "description": "some lead", + "dependencies": {}, + "testDependency": "li-test-dependency.onUpdate is correct" + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "Obama re-elected", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + } + ] + +- code: "200" + endpoint: /api/v1/publications/search?categories=sport,fashion&languages=en + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "article", + "documentType": "article", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "Bayern to win Champions League", + "description": "some lead", + "category": { + "id": "sport" + }, + "language": { + "locale": "en" + }, + "dependencies": {}, + "testDependency": "li-test-dependency.onUpdate is correct" + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "Bayern to win Champions League", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + } + ] + +- code: "200" + endpoint: /api/v1/publications/search?contentTypes=regular,gallery&limit=10&offset=10 + body: | + [ + { + "systemdata": { + "projectId": 1, + "channelId": 1, + "documentId": 1, + "contentType": "regular", + "documentType": "article", + "design": { + "name": "timeline", + "version": "1.1.0" + } + }, + "metadata": { + "title": "Bayern to win Champions League", + "description": "some lead", + "category": { + "id": "sport" + }, + "language": { + "locale": "en" + }, + "dependencies": {}, + "testDependency": "li-test-dependency.onUpdate is correct" + }, + "content": [ + { + "id": "doc-1b8i1ksh10", + "component": "head", + "identifier": "timeline.head", + "content": { + "title": "Bayern to win Champions League", + "text": "some lead" + } + }, + { + "id": "doc-1b8i1ksh20", + "component": "normal", + "identifier": "timeline.normal", + "content": { + "caption": "my caption" + }, + "styles": { + "position": "left" + } + }, + { + "id": "doc-1b8i1ksh30", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "first paragraph" + } + }, + { + "id": "doc-1b8i1me1d0", + "component": "p", + "identifier": "timeline.p", + "content": { + "text": "second paragraph" + } + } + ] + } + ] + +- code: "200" + endpoint: /api/v1/publications/search?contentTypes=article&limit=999&fields=id + body: | + [ + { + "documentId": 1, + "projectId": 1 + }, + { + "documentId": 2, + "projectId": 1 + } + ] diff --git a/content/reference/public-api/retresco.md b/content/reference/public-api/retresco.md deleted file mode 100644 index 11670af91..000000000 --- a/content/reference/public-api/retresco.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Retresco re-enrich -weight: 15 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Re-enrich documents with Retresco" - scopes="retresco" ->}} - -{{< added-in "release-2023-03" >}} - ---query-- -```bash -ACCESS_TOKEN=ey1234 -curl -k -X POST "https://server.livingdocs.io/api/v1/retresco/re-enrich" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json; charset=utf-8" \ - --data-binary @- << EOF - { - "doc_ids": ["1", "2", "3"] - } -EOF -``` - ---endpoint-- -``` -GET /api/v1/retresco/re-enrich -``` - ---parameters-- - -|Name|Type|Notes| -|-|-|-| -|doc_ids|array\|A list of the desired document ids to re-enrich.| - ---description-- - -Re-enriches documents with Retresco. This endpoint is only available for customers with a [Retresco integration enabled]({{< ref "/guides/integrations/retresco" >}}). The endpoint will return a 200 status code when the request is valid, then the Livingdocs Server will start the re-enrichment process in the background. The re-enrichment process can take up to 1s per document to re-enrich. If the provided document ids are not found, the re-enrich job will not be executed for that document. - -Follow the [guide to configure the re-enrich webhook]({{< ref "/guides/integrations/retresco#re-enrich-documents" >}}) in Retresco's website. - -Use Cases: - -- Re-enrich documents after modifications in the Retresco entities, to update the document metadata. This endpoint should be called by Retresco when the user modifies entities that apply to one or multiple documents. - ---response-- -200 ---- -api/v1/retresco/re-enrich ---- -```js -{ -} -``` ------ -400 ---- -api/v1/retresco/re-enrich ---- -```js -{ - "status":400, - "error":"Bad Request", - "error_details": - { - "message":"The Retresco API has not been enabled (projectId=5)", - "name":"ConfigurationError" - } -} -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/retresco/_index.md b/content/reference/public-api/retresco/_index.md new file mode 100644 index 000000000..63cbb764b --- /dev/null +++ b/content/reference/public-api/retresco/_index.md @@ -0,0 +1,10 @@ +--- +title: Retresco re-enrich +weight: 15 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="retresco_re_enrich.yaml" >}} diff --git a/content/reference/public-api/retresco/retresco_re_enrich.yaml b/content/reference/public-api/retresco/retresco_re_enrich.yaml new file mode 100644 index 000000000..da07eec27 --- /dev/null +++ b/content/reference/public-api/retresco/retresco_re_enrich.yaml @@ -0,0 +1,45 @@ +title: Re-enrich documents with Retresco +description: | + Re-enriches documents with Retresco. This endpoint is only available for customers with a [Retresco integration enabled]({{< ref "/guides/integrations/retresco" >}}). The endpoint will return a 200 status code when the request is valid, then the Livingdocs Server will start the re-enrichment process in the background. The re-enrichment process can take up to 1s per document to re-enrich. If the provided document ids are not found, the re-enrich job will not be executed for that document. + + Follow the [guide to configure the re-enrich webhook]({{< ref "/guides/integrations/retresco#re-enrich-documents" >}}) in Retresco's website. + +useCases: | + - Re-enrich documents after modifications in the Retresco entities, to update the document metadata. This endpoint should be called by Retresco when the user modifies entities that apply to one or multiple documents. + +added: release-2023-03 +scopes: retresco +query: | + ACCESS_TOKEN=ey1234 + curl -k -X POST "https://server.livingdocs.io/api/v1/retresco/re-enrich" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json; charset=utf-8" \ + --data-binary @- << EOF + { + "doc_ids": ["1", "2", "3"] + } + EOF +endpoint: + method: GET + path: /api/v1/retresco/re-enrich +parameters: + - name: ?doc_ids + type: array + notes: "A list of the desired document ids to re-enrich." +responses: + - code: "200" + endpoint: /api/v1/retresco/re-enrich + body: | + {} + - code: "400" + endpoint: /api/v1/retresco/re-enrich + body: | + { + "status":400, + "error":"Bad Request", + "error_details": + { + "message":"The Retresco API has not been enabled (projectId=5)", + "name":"ConfigurationError" + } + } diff --git a/content/reference/public-api/routing.md b/content/reference/public-api/routing.md deleted file mode 100644 index 1b73b3d14..000000000 --- a/content/reference/public-api/routing.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Routing -weight: 13 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Resolve a Path to a Document" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/routing/resolve?path=:path" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/routing/resolve -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|?path|string|x|Path to the document.
Example 1: A page with a category `/news` can be found with `?path=/news.html`.
Example 2: A document with id 10, with category `/news` and a slug `hello` can be found with `?path=/magazin/hello-10.html'`.| - ---description-- -You need to activate the [Categories]({{< ref "/reference/project-config/categories" >}}) / [Routing]({{< ref "/reference/project-config/content-types#routing" >}}) feature in the Project Config in order to resolve paths to your documents. Routing is a quite advanced topic and the examples only work with a default configuration. Find more [here](/guides/organisation/routing-system/). ---response-- -200 ---- -api/v1/routing/resolve?path=/correct-path/my-article-173.html ---- -```js -[ - { - "type": "document", - "resource": { - "id": 173, - "statusCode": 200 - } - } -] -``` ------ -301 ---- -api/v1/routing/resolve?path=/incorrect-path/slug-with-correct-id-77.html ---- -```js -[ - { - "type": "redirect", - "path": "/path/to/redirect", - "resource": { - "statusCode": 301 - } - } -] -``` ------ -404 ---- -api/v1/routing/resolve?path=/does/not/exist ---- -```js -{ - "status": 404, - "error": "Not Found" -} -``` ------ -410 ---- -api/v1/routing/resolve?path=/unpublished-document-123.html ---- -```js -[ - { - "type": "unpublished", - "resource": { - "id": 123, - "statusCode": 410 - } - } -] -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/routing/_index.md b/content/reference/public-api/routing/_index.md new file mode 100644 index 000000000..eea4657cc --- /dev/null +++ b/content/reference/public-api/routing/_index.md @@ -0,0 +1,10 @@ +--- +title: Routing +weight: 13 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="resolve_path.yaml" >}} diff --git a/content/reference/public-api/routing/resolve_path.yaml b/content/reference/public-api/routing/resolve_path.yaml new file mode 100644 index 000000000..dee96c0ff --- /dev/null +++ b/content/reference/public-api/routing/resolve_path.yaml @@ -0,0 +1,64 @@ +title: Resolve a Path to a Document +description: | + You need to activate the [Categories]({{< ref "/reference/project-config/categories" >}}) / [Routing]({{< ref "/reference/project-config/content-types#routing" >}}) feature in the Project Config in order to resolve paths to your documents. Routing is a quite advanced topic and the examples only work with a default configuration. Find more [here](/guides/organisation/routing-system/). + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/routing/resolve?path=:path" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/routing/resolve +parameters: + - name: path + type: string + required: true + notes: | + Path to the document. + Example 1: A page with a category `/news` can be found with `?path=/news.html`. + Example 2: A document with id 10, with category `/news` and a slug `hello` can be found with `?path=/magazin/hello-10.html'`. +responses: + - code: "200" + endpoint: /api/v1/routing/resolve?path=/correct-path/my-article-173.html + body: | + [ + { + "type": "document", + "resource": { + "id": 173, + "statusCode": 200 + } + } + ] + - code: "301" + endpoint: /api/v1/routing/resolve?path=/incorrect-path/slug-with-correct-id-77.html + body: | + [ + { + "type": "redirect", + "path": "/path/to/redirect", + "resource": { + "statusCode": 301 + } + } + ] + - code: "404" + endpoint: /api/v1/routing/resolve?path=/does/not/exist + body: | + { + "status": 404, + "error": "Not Found" + } + - code: "410" + endpoint: /api/v1/routing/resolve?path=/unpublished-document-123.html + body: | + [ + { + "type": "unpublished", + "resource": { + "id": 123, + "statusCode": 410 + } + } + ] diff --git a/content/reference/public-api/sitemaps.md b/content/reference/public-api/sitemaps.md deleted file mode 100644 index bab613cfa..000000000 --- a/content/reference/public-api/sitemaps.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Sitemaps -weight: 11 -renderTOC: false -menus: - reference: - parent: Public API ---- - -{{< api-example - title="Get a Sitemap's Index" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/sitemaps/index?baseUrl=https://livingdocs.io" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/sitemaps/index -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:baseUrl|string|x|Base url of the delivery host. Example: `?baseUrl=https://livingdocs.io/`| -|:contentTypes|string||A comma-separated list of contentTypes to include in the sitemap. Example: `?contentTypes=regular,pages`| -|:entriesPerPage|string||Optional sitemap entry page size. Default 20000| - ---description-- - -This endoint returns a sitemap index containing links to individual sitemap files. The [Sitemap Guide]({{< ref "/guides/organisation/sitemaps-and-feeds" >}}) explains how to setup sitemaps for a Livingdocs delivery. - -##### Use Cases - -- Provides a [Sitemap Index](https://www.sitemaps.org/protocol.html) for Deliveries (linked via robots.txt) - ---response-- -200 ---- ---- -```xml - - - https://www.livingdocs.io/sitemap.2020-01.xml - 2020-01-31T22:54:23.125Z - - - https://www.livingdocs.io/sitemap.2020-02.xml - 2020-02-29T21:07:31.544Z - - - https://www.livingdocs.io/sitemap.2020-02.2.xml - 2020-02-29T21:07:31.544Z - - - https://www.livingdocs.io/sitemap.2020-02.3.xml - 2020-02-29T21:07:31.544Z - - -``` - -{{< /api-example >}} - -{{< api-example - title="Get a Sitemap's Entries" - scopes="public-api:read" ->}} - ---query-- - -```bash -ACCESS_TOKEN=ey1234 -curl -k -X GET "https://server.livingdocs.io/api/v1/sitemaps/entries?baseUrl=https://livingdocs.io&date=2021-05" \ - -H "Authorization: Bearer $ACCESS_TOKEN" -``` - ---endpoint-- -``` -GET api/v1/sitemaps/entries -``` - ---parameters-- -|Name|Type|Required|Notes| -|-|-|-|-| -|:baseUrl|string|x|Base url of the delivery host. Example: `?baseUrl=https://livingdocs.io/`| -|:date|string|x|Date for the specific month matching the schema from the sitemap index file. Example: `?date=2021-06` or `?date=2021-06.2`| -|:contentTypes|string||A comma-separated list of contentTypes to include in the sitemap. Example: `?contentTypes=regular,pages`| -|:entriesPerPage|string||Optional sitemap entry page size. Default 20000| - ---description-- - -##### Use Cases - -- Provides [Sitemap Entries](https://www.sitemaps.org/protocol.html) for Deliveries - ---response-- -200 ---- ---- -```xml - - - https://www.livingdocs.io/category/title-li.1 - 2021-05-01T04:56:50.276Z - - - https://www.livingdocs.io/category/title-li.2 - 2021-05-01T05:35:32.920Z - - -``` - -{{< /api-example >}} diff --git a/content/reference/public-api/sitemaps/_index.md b/content/reference/public-api/sitemaps/_index.md new file mode 100644 index 000000000..ff83965dc --- /dev/null +++ b/content/reference/public-api/sitemaps/_index.md @@ -0,0 +1,12 @@ +--- +title: Sitemaps +weight: 11 +renderTOC: false +menus: + reference: + parent: Public API +--- + +{{< api-example-resource file="get_sitemap_index.yaml" >}} + +{{< api-example-resource file="get_sitemap_entries.yaml" >}} diff --git a/content/reference/public-api/sitemaps/get_sitemap_entries.yaml b/content/reference/public-api/sitemaps/get_sitemap_entries.yaml new file mode 100644 index 000000000..fecf2ec16 --- /dev/null +++ b/content/reference/public-api/sitemaps/get_sitemap_entries.yaml @@ -0,0 +1,50 @@ +title: Get a Sitemap's Entries +useCases: | + - Provides [Sitemap Entries](https://www.sitemaps.org/protocol.html) for Deliveries + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/sitemaps/entries?baseUrl=https://livingdocs.io&date=2021-05" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/sitemaps/entries +parameters: + - name: ?baseUrl + type: string + required: true + notes: | + Base url of the delivery host. + Example: `?baseUrl=https://livingdocs.io/` + + - name: ?date + type: string + required: true + notes: | + Date for the specific month matching the schema from the sitemap index file. + Example: `?date=2021-06` or `?date=2021-06.2` + - name: ?contentTypes + type: string + required: false + notes: | + A comma-separated list of contentTypes to include in the sitemap. + Example: `?contentTypes=regular,pages` + - name: ?entriesPerPage + type: string + required: false + notes: Optional sitemap entry page size. Default 20000 +responses: + - code: "200" + format: xml + body: | + + + https://www.livingdocs.io/category/title-li.1 + 2021-05-01T04:56:50.276Z + + + https://www.livingdocs.io/category/title-li.2 + 2021-05-01T05:35:32.920Z + + diff --git a/content/reference/public-api/sitemaps/get_sitemap_index.yaml b/content/reference/public-api/sitemaps/get_sitemap_index.yaml new file mode 100644 index 000000000..b51abd0ac --- /dev/null +++ b/content/reference/public-api/sitemaps/get_sitemap_index.yaml @@ -0,0 +1,54 @@ +title: Get a Sitemap's Index +description: | + This endoint returns a sitemap index containing links to individual sitemap files. The [Sitemap Guide]({{< ref "/guides/organisation/sitemaps-and-feeds" >}}) explains how to setup sitemaps for a Livingdocs delivery. + +useCases: | + - Provides a [Sitemap Index](https://www.sitemaps.org/protocol.html) for Deliveries (linked via robots.txt) + +scopes: public-api:read +query: | + ACCESS_TOKEN=ey1234 + curl -k -X GET "https://server.livingdocs.io/api/v1/sitemaps/index?baseUrl=https://livingdocs.io" \ + -H "Authorization: Bearer $ACCESS_TOKEN" +endpoint: + method: GET + path: /api/v1/sitemaps/index +parameters: + - name: ?baseUrl + type: string + required: true + notes: | + Base url of the delivery host. + Example: `?baseUrl=https://livingdocs.io/` + - name: ?contentTypes + type: string + required: false + notes: | + A comma-separated list of contentTypes to include in the sitemap. + Example: `?contentTypes=regular,pages` + - name: ?entriesPerPage + type: string + required: false + notes: Optional sitemap entry page size. Default 20000 +responses: + - code: "200" + format: xml + body: | + + + https://www.livingdocs.io/sitemap.2020-01.xml + 2020-01-31T22:54:23.125Z + + + https://www.livingdocs.io/sitemap.2020-02.xml + 2020-02-29T21:07:31.544Z + + + https://www.livingdocs.io/sitemap.2020-02.2.xml + 2020-02-29T21:07:31.544Z + + + https://www.livingdocs.io/sitemap.2020-02.3.xml + 2020-02-29T21:07:31.544Z + + diff --git a/package.json b/package.json index 6df9734f5..c444829d9 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "build": "./bin/build.sh", "build:fast": "./bin/build.sh --fast", - "start": "exec hugo server --buildDrafts --buildFuture --openBrowser", + "start": "exec hugo server --buildDrafts --buildFuture --openBrowser --navigateToChanged", "start:production": "serve ./public" }, "repository": { diff --git a/themes/hugo-docs/assets/elements/api-example.scss b/themes/hugo-docs/assets/elements/api-example.scss index 7074b4869..a29693008 100644 --- a/themes/hugo-docs/assets/elements/api-example.scss +++ b/themes/hugo-docs/assets/elements/api-example.scss @@ -43,6 +43,15 @@ $api-example-padding: $space-m; hyphens: auto; width: 60%; } + + p { + font-size: 1em; + margin-bottom: 1em; + + &:last-child { + margin-bottom: 0; + } + } } &__description, diff --git a/themes/hugo-docs/layouts/_default/_markup/render-blockquote.html b/themes/hugo-docs/layouts/_default/_markup/render-blockquote.html new file mode 100644 index 000000000..17c5a8e98 --- /dev/null +++ b/themes/hugo-docs/layouts/_default/_markup/render-blockquote.html @@ -0,0 +1,26 @@ +{{ $emojis := dict + "caution" ":exclamation:" + "important" ":information_source:" + "note" ":information_source:" + "tip" ":bulb:" + "warning" ":information_source:" +}} + +{{ if eq .Type "alert" }} +
+

+ {{ $info := resources.Get (printf "svg/%s.svg" .AlertType) | fingerprint }} + + {{ with .AlertTitle }} + {{ . }} + {{ else }} + {{ or (i18n .AlertType) (title .AlertType) }} + {{ end }} +

+ {{ .Text }} +
+{{ else }} +
+ {{ .Text }} +
+{{ end }} diff --git a/themes/hugo-docs/layouts/shortcodes/api-example-resource.html b/themes/hugo-docs/layouts/shortcodes/api-example-resource.html new file mode 100644 index 000000000..4574e3ff7 --- /dev/null +++ b/themes/hugo-docs/layouts/shortcodes/api-example-resource.html @@ -0,0 +1,132 @@ +{{- $yamlPath := .Get "file" -}} +{{ $PAGE := .Page }} +{{ if (ne $PAGE.BundleType "branch") }}{{ $PAGE = .Page.Parent }}{{ end }} +{{- $example := $PAGE.Resources.Get $yamlPath | transform.Unmarshal -}} + +
+ + {{- if $example.title -}} +

{{ $example.title | $PAGE.RenderString }}

+ {{- end -}} + + {{- if $example.release -}} + {{- partial "added-in" (dict "release" $example.release "block" true) -}} + {{- end -}} + + {{- if $example.deprecation -}} + {{ (printf `> [!WARNING] {{< deprecated-in "%s" >}}

%s` $example.deprecation.since $example.deprecation.note) | $PAGE.RenderString }} + {{- end -}} + + {{- if $example.scopes -}} + {{- partial "required-for" (dict "scopes" $example.scopes "block" true) -}} + {{- end -}} + + {{- if $example.description -}} +
+

Description

+ {{- $example.description | $PAGE.RenderString -}} +
+ {{- end -}} + + {{- if $example.useCases -}} +
+

Use Cases

+ {{- $example.useCases | $PAGE.RenderString -}} +
+ {{- end -}} + + {{- if $example.query -}} +
+
+
+
+
+ +
+
Curl Example
+
+
+ +
+ {{ highlight $example.query "bash" }} +
+
+
+ {{- end -}} + + {{- if $example.endpoint -}} +

Endpoint

+ {{ highlight (printf "%s %s" $example.endpoint.method $example.endpoint.path) "curl" }} + {{- end -}} + + {{- if $example.parameters -}} +

Parameters

+ + + + + + + + + + + {{- range $example.parameters -}} + + + + + + + {{- end -}} + +
NameTypeRequiredNotes
{{ .name }}{{ .type }}{{ if .required }}x{{ end }}{{ .notes | $PAGE.RenderString }}
+ {{- end -}} + + {{- if $example.example_request -}} +

Example Request

+ {{ highlight $example.example_request "js" }} + {{- end -}} + + {{- if $example.responses -}} +
+

Response{{ if (eq $example.responseBlurry true) }} (may differ in details){{ end }}

+ + {{- range $example.responses -}} +
+
+
+
+ {{ if (ne .collapsible false) }} +
+ +
+ {{ end }} +
{{ .code }}
+ {{ $routename := "" }} + {{- if .name -}}{{ $routename = .name }} + {{- else if (eq .code "200") -}}{{ $routename = "OK" }} + {{- else if (eq .code "301") -}}{{ $routename = "Moved Permanently" }} + {{- else if (eq .code "400") -}}{{ $routename = "Bad Request" }} + {{- else if (eq .code "401") -}}{{ $routename = "Unauthorized" }} + {{- else if (eq .code "403") -}}{{ $routename = "Forbidden" }} + {{- else if (eq .code "404") -}}{{ $routename = "Not Found" }} + {{- else if (eq .code "409") -}}{{ $routename = "Conflict" }} + {{- else if (eq .code "429") -}}{{ $routename = "Usage Limit Exceeded" }} + {{- else if (eq .code "500") -}}{{ $routename = "Bad Request" }} + {{ end}} + {{- if $routename -}}
{{ $routename }}
{{ end }} + {{- if .endpoint -}}
{{ .endpoint }}
{{- end -}} +
+
+
+ {{ highlight .body (or .format "js") }} +
+
+
+ {{- end -}} + +
+ {{- end -}} + +
diff --git a/themes/hugo-docs/layouts/shortcodes/api-example.html b/themes/hugo-docs/layouts/shortcodes/api-example.html deleted file mode 100644 index edbb1dc81..000000000 --- a/themes/hugo-docs/layouts/shortcodes/api-example.html +++ /dev/null @@ -1,111 +0,0 @@ -{{- $title := .Get "title" -}} -{{- $release := .Get "release" -}} -{{- $scopes := .Get "scopes" -}} -{{- $beta := .Get "beta" -}} -{{- $showResponseCode := .Get "showResponseCode" -}} -{{- $responseBlurry := .Get "responseBlurry" -}} - -{{- $segments := split .Inner "--query--" -}} - -{{- $segmentsQuery := split (index $segments 1) "--endpoint--" -}} -{{- $segmentsEndpoint := split (index $segmentsQuery 1) "--parameters--" -}} -{{- $segmentsParameters := split (index $segmentsEndpoint 1) "--description--" -}} -{{- $segmentsDescription := split (index $segmentsParameters 1) "--response--" -}} -{{- $segmentsResponse := split (index $segmentsDescription 1) "-----" -}} - -{{- $query := index $segmentsQuery 0 | markdownify -}} -{{- $endpoint := index $segmentsEndpoint 0 | markdownify -}} -{{- $parameters := index $segmentsParameters 0 | markdownify -}} -{{- $description := index $segmentsDescription 0 | markdownify -}} - -
- - {{- if (ne $title "") -}} -

{{ $title | markdownify }}

- {{- end -}} - - {{- if (ne $release "") -}} - {{- partial "added-in" (dict "release" $release "block" true) -}} - {{- end -}} - - {{- if (ne $scopes "") -}} - {{- partial "required-for" (dict "scopes" $scopes "block" true) -}} - {{- end -}} - - {{- if (ne $description "") -}} -
-

Description

- {{- $description -}} -
- {{- end -}} - - {{- if (ne $query "") -}} -
-
-
-
-
- -
-
Curl Example
-
-
- -
- {{- $query -}} -
-
-
- {{- end -}} - - {{- if (ne $endpoint "") -}} -

Endpoint

- {{- $endpoint -}} - {{- end -}} - - {{- if (ne $parameters "") -}} -

Parameters

- {{- $parameters -}} - {{- end -}} - - {{- if (ne (index $segmentsResponse 0) "") -}} -
-

Response{{ if (eq $responseBlurry true) }} (may differ in details){{ end }}

- - {{- range $item, $segmentsResponse -}} - {{- $code := index (split $item "---") 0 | markdownify -}} - {{- $endpoint := index (split $item "---") 1 | markdownify -}} - {{- $script := index (split $item "---") 2 | markdownify -}} - -
-
-
-
-
- -
- -
{{ $code }}
- {{- if (eq $code "200") -}}
OK
{{- end -}} - {{- if (eq $code "301") -}}
Moved Permanently
{{- end -}} - {{- if (eq $code "400") -}}
Bad Request
{{- end -}} - {{- if (eq $code "401") -}}
Unauthorized
{{- end -}} - {{- if (eq $code "403") -}}
Forbidden
{{- end -}} - {{- if (eq $code "404") -}}
Not Found
{{- end -}} - {{- if (eq $code "409") -}}
Conflict
{{- end -}} - {{- if (eq $code "429") -}}
Usage Limit Exceeded
{{- end -}} - {{- if (eq $code "500") -}}
Bad Request
{{- end -}} - {{- if (ne $endpoint "") -}}
{{ $endpoint }}
{{- end -}} -
-
-
- {{- $script -}} -
-
-
- {{- end -}} - -
- {{- end -}} - -