A Webhook notifies another system via a HTTP POST request about a change in Livingdocs, e.g. when a document has been published. You can configure multiple Webhooks that are called on only one or multiple events.
Configuration
The Webhooks feature is enabled by default, but can get disabled via Server Configuration.
One or multiple Webhooks are configured via Project Config (see example below):
// Project Config settings.webhooks
webhooks: {
active: true
configurations: [
{
// unique handle per project
handle: 'my-webhook',
// shown label in UI
label: 'My Webhook',
description: 'A description for future self and coworkers',
// called url with a POST request when a selected event happens
url: 'https://example.com/my-webhook-endpoint',
// sign request with HTTP header 'x-livingdocs-signature'
// 1) empty -> no sign request
// 2) 'a-secret-token-to-sign-the-request' -> sign request with token
// 3) {$secretRef: {name: 'webhook-local'}} -> sign request with project secret
// see below a more detailled description
secret: 'a-secret-token-to-sign-the-request'
// a webhook only gets called when this is set to true
active: true
// this webhook only gets called when this event happens
events: [
'document.publish',
'document.unpublish',
{
name: 'document.update',
changeFilter: {
metadataProperties: [
'title'
]
}
},
{
name: 'document.build',
conditions: {
// deliveries configured in the Project Config
deliveryHandles: [
'web',
'desktop'
]
}
},
'mediaLibraryEntry.create',
'mediaLibraryEntry.archive',
'mediaLibraryEntry.revoke',
'mediaLibraryEntry.update'
]
}
]
}
List of Available Webhook Events
document.publish
document.unpublish
document.update
document.build
document.build.draft
mediaLibraryEntry.create
mediaLibraryEntry.archive
mediaLibraryEntry.revoke
mediaLibraryEntry.update
Testing Webhooks
For quickly testing Webhooks we use https://webhook.site. It gives you an URL you can use to send webhooks to and look at all the requests in a webinterface.
Webhook Config via Editor UI
We strongly propose adding Webhook configs via Project Config, but we also provide a UI in the Editor.
In the project menu, select “Project Setup”, then select “Webhooks” in the “Configuration” section of the menu. You can activate/deactivate all your configured webhooks using the setting “deliver webhooks on events”.

Add a new Webhook by clicking “Add Webhook” or edit an existing one by clicking on it’s entry in the list. This shows a form to configure the webhook.

Payload
Here is an example payload sent to your url set in the Webhook configuration.
document.publish
{
"event": "document.publish",
"deliveryId": "qy8qoxQPVCES1VDneg4FE", // unique id on every call
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"documentId": 179,
"publicationEvent": {
"createdAt": "2021-02-16T18:04:50.203Z",
"contentType": "regular",
"documentType": "article",
"eventType": "publish",
"publicationId": 174,
"projectId": 3,
"channelId": 4,
"documentId": 179
}
}
document.unpublish
{
"event": "document.unpublish",
"deliveryId": "p3QA1OhXkQGJepVTkdd1b",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"documentId": 179,
"publicationEvent": {
"createdAt": "2021-02-16T18:04:51.285Z",
"contentType": "regular",
"documentType": "article",
"eventType": "unpublish",
"publicationId": 174,
"projectId": 3,
"channelId": 4,
"documentId": 179
}
}
document.update
{
"event": "document.update",
"deliveryId": "B_-8BAfgvuJRKk7m_RSls",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"documentId": 179,
"metadataPropertyChanges": [
"title"
]
}
document.build
{
"event": "document.build",
"deliveryId": "2Xwe-gvuB_JsK3_4bJerT",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"documentId": 179,
"publicationId": 322,
"deliveryHandle": "web",
"reportId": "2SG2MAA9RwPn"
}
document.build.draft
{
"event": "document.build",
"deliveryId": "2Xwe-gvuB_JsK3_4bJerT",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"documentId": 179,
"deliveryHandle": "web",
"reportId": "2SG2MAA9RwPn"
}
mediaLibraryEntry.create
{
"event": "mediaLibraryEntry.create",
"deliveryId": "f8K1HZ-_fTIf5kT698NqG",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"mediaId": "PNIi08x4UdEA"
}
mediaLibraryEntry.update
{
"event": "mediaLibraryEntry.update",
"deliveryId": "_p6aKe9Len6WnlvANDJSz",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"mediaId": "PNIi08x4UdEA"
}
mediaLibraryEntry.archive
{
"event": "mediaLibraryEntry.archive",
"deliveryId": "gmWn5OfOsZzEiY3FNRgA4",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"mediaId": "PNIi08x4UdEA"
}
mediaLibraryEntry.revoke
{
"event": "mediaLibraryEntry.revoke",
"deliveryId": "J1FrTJTNKKRoGmjBlQ3_e",
"projectId": 3,
"projectHandle": "service",
"webhookHandle": "handle",
"mediaId": "PNIi08x4UdEA"
}
Validate Webhook Signature on your Endpoint
If you have defined a secret
for your Webhook, Livingdocs creates a signature of the payload and sends it with the request in the HTTP header x-livingdocs-signature
.
The signature is created using HMAC-SHA256 and will be sent in x-livingdocs-signature
in the form sha256=<hex digest>
for example sha256=d8a47af83666a771d57117aa28ef8d3243a3de43
.
Here is sample code in JavaScript to validate the signature on your endpoint:
// set payload to the body received with the request to your endpoint
const payload = JSON.stringify(request.body)
const signature = request.headers['x-livingdocs-signature']
// secret needs to be the same you configured with the webhook in livingdocs
const secret = 'a-secret-token-to-sign-the-request' // you should not hardcode this but read it from an environment variable
// compute the hmac on the received payload using the same secret
const crypto = require('crypto')
const hmac = crypto.createHmac('sha256', secret)
const payloadSignature = Buffer.from(`sha256=${hmac.update(payload).digest('hex')}`, 'utf8')
const checksum = Buffer.from(signature, 'utf8')
// use timingSafeEqual to compare the signature sent from livingdocs with the computed checksum
if (crypto.timingSafeEqual(payloadSignature, checksum)) {
// payload is valid, move on
} else {
// abort, this is not a valid request
}