Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 88 additions & 63 deletions 15/umbraco-cms/reference/webhooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ description: Umbraco webhooks enable seamless integration and real-time updates

# Webhooks

Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows you to integrate with third-party services, automate workflows, and synchronize data effortlessly.
Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows developers to integrate with third-party services, automate workflows, and synchronize data effortlessly.

## Getting Started

To manage webhooks, navigate to **Settings > Webhooks** in the Umbraco backoffice.

![Webhooks section](images/webhook-section-v14.png)
Expand All @@ -17,13 +16,10 @@ To create a webhook, click **Create**. This opens the webhook creation screen wh
![Creating a webhook](images/create-webhook-v14.png)

## Configuring a Webhook

### URL

The `Url` is the endpoint where the webhook will send an HTTP request when the selected event is triggered. Ensure this endpoint is publicly accessible and capable of handling incoming requests.

### Events

Webhooks are triggered by specific events in Umbraco. By default, the following events are available:

| Event Name | Description |
Expand All @@ -35,48 +31,69 @@ Webhooks are triggered by specific events in Umbraco. By default, the following
| Media Saved | Fires when a media item is saved. |

### Content Type Filtering

For **Content** or **Media** events, you can specify whether the webhook should trigger for all content types or only specific ones. This is useful when you only need webhooks for certain document types, such as blog posts or products.
For **Content** or **Media** events, developers can specify whether the webhook should trigger for all content types or only specific ones. This is useful when activating webhooks for certain document types, such as blog posts or products.

### Custom Headers

You can define custom HTTP headers that will be included in the webhook request. Common use cases include:
Developers can define custom HTTP headers that will be included in the webhook request. Common use cases include:

- Specifying request format: `Accept: application/json`
- Adding authentication tokens: `Authorization: Bearer <your-token>`
- Including security headers

## Default Behavior of Umbraco Webhooks

Umbraco webhooks come with predefined settings and behaviors.

### JSON Payload
Each webhook event sends a JSON payload. The following types of payloads are available by default.

Each webhook event sends a JSON payload. For example, the `Content Published` event includes full content details:
#### Legacy
This is the current default but will be removed in a future version. Legacy payloads follow the format used before version 16. They are inconsistent and may include data that should not be exposed or has been superseded (e.g., use of `int` instead of `Guid`).

```json
#### Minimal
This will become the default in version 17 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This will become the default in version 17 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures.
This will become the default in version 18 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures.

@Migaroez - just checking this update with you, but I believe we decided to keep legacy as the default to avoid an unnecessary breaking change in 17.


#### Extended
Extended payloads include all relevant information for an event, where available. However, sensitive data, such as usernames, member names, or email addresses, is excluded for privacy and security reasons. If an extended payload is not available for an event, the system falls back to the minimal payload.

### Configuring Payload Types
Payload type can be configured in the following ways:

- Changing the appsetting `Umbraco:CMS:Webhook:PayloadType`. Be aware that the system that uses this value runs before any composers. If you manipulate the `WebhookEventCollectionBuilder` in any way, then those methods will not automatically pick up this app setting.
- Passing in the PayloadType into the `WebhookEventCollectionBuilderExtensions` methods to control which webhook events are added.

```csharp
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Webhooks;

namespace Umbraco.Cms.Web.UI.Composers;

// this composer clears all registered webhooks and then adds all (umbraco provided) webhooks with their extended payloads
public class AllWebhookComposer : IComposer
{
"name": "Root",
"createDate": "2023-12-11T12:02:38.9979314",
"updateDate": "2023-12-11T12:02:38.9979314",
"route": {
"path": "/",
"startItem": {
"id": "c1922956-7855-4fa0-8f2c-7af149a92135",
"path": "root"
public void Compose(IUmbracoBuilder builder)
{
builder.WebhookEvents().Clear().AddCms(onlyDefault: false, payloadType: WebhookPayloadType.Extended);
}
},
"id": "c1922956-7855-4fa0-8f2c-7af149a92135",
"contentType": "root",
"properties": {}
}

```

The `Content Deleted` event sends only the content ID:
- Manually manipulating the `WebhookEventCollectionBuilder`.

```json
```csharp
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Webhooks.Events;

namespace Umbraco.Cms.Web.UI.Composers;

// since legacy is the default, this composer removes the old content published webhookevent and changes it with the new extended version.
public class AllWebhookComposer : IComposer
{
"id": "c1922956-7855-4fa0-8f2c-7af149a92135"
public void Compose(IUmbracoBuilder builder)
{
builder.WebhookEvents().Remove<LegacyContentPublishedWebhookEvent>();
builder.WebhookEvents().Add<ExtendedContentPublishedWebhookEvent>();
}
}
```

Expand Down Expand Up @@ -138,50 +155,53 @@ builder.WebhookEvents().Clear().AddCms(false);

### Replacing Webhook Events

You can modify existing webhook events, such as changing the payload format, by creating a custom implementation:
Developers can modify existing webhook events, such as changing the payload format, by creating a custom implementation:

```csharp
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Webhooks;

namespace CommunityDocs.Controllers;

[WebhookEvent("Content Published", Constants.WebhookEvents.Types.Content)]
public class MyCustomContentPublishedWebhookEvent : WebhookEventContentBase<ContentPublishedNotification, IContent>
public class MyCustomContentPublishedWebhookEvent(
IWebhookFiringService webhookFiringService,
IWebhookService webhookService,
IOptionsMonitor<WebhookSettings> webhookSettings,
IServerRoleAccessor serverRoleAccessor,
IApiContentBuilder apiContentBuilder,
IPublishedContentCache publishedContentCache):
WebhookEventContentBase<ContentPublishedNotification, IContent>(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor)
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IApiContentBuilder _apiContentBuilder;

public MyCustomContentPublishedWebhookEvent(
IWebhookFiringService webhookFiringService,
IWebhookService webhookService,
IOptionsMonitor<WebhookSettings> webhookSettings,
IServerRoleAccessor serverRoleAccessor,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IApiContentBuilder apiContentBuilder)
: base(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_apiContentBuilder = apiContentBuilder;
}

public override string Alias => "Umbraco.ContentPublish";
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities;

protected override object? ConvertEntityToRequestPayload(IContent entity)
{
if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null)
{
return null;
}

IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key);
var cachedPublishedContent = publishedContentCache.GetById(entity.Key);

return new
{
CustomData = "Your data",
PublishedContent = publishedContent is null ? null : _apiContentBuilder.Build(publishedContent)
PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent)
};
}
}
```

To replace the default Umbraco webhook with your custom implementation:
{% hint style="info" %}
Umbraco developers will need to inject `IPublishedContentCache`, `IPublishedMediaCache`, `IPublishedMemberCache` and `IPublishedContentTypeCache` dependencies individually, instead of injecting the `IPublishedSnapshotAccessor` as would have been done previously.
{% endhint %}

The code below shows an example that replaces the default Umbraco webhook with a custom implementation:

```csharp
public class MyComposer : IComposer
Expand All @@ -197,19 +217,24 @@ public class MyComposer : IComposer

Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`:

{% code title="appsettings.json" %}
```json
"Umbraco": {
"CMS": {
"Webhook": {
"Enabled": true,
"MaximumRetries": 5,
"Period": "00:00:10",
"EnableLoggingCleanup": true,
"KeepLogsForDays": 30
{
"$schema": "appsettings-schema.json",
"Umbraco": {
"CMS": {
"Webhook": {
"Enabled": true,
"MaximumRetries": 5,
"Period": "00:00:10",
"EnableLoggingCleanup": true,
"KeepLogsForDays": 30
}
}
}
}
}
```
{% endcode %}

| Setting | Description |
|---------|-------------|
Expand All @@ -221,4 +246,4 @@ Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`:

## Testing Webhooks

Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test your event trigger integrations before deploying them to production.
Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test the event trigger integrations before deploying them to production.
42 changes: 20 additions & 22 deletions 15/umbraco-cms/reference/webhooks/expanding-webhook-events.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
---
description: >-
Explore new webhook event options, detailed setup, specific content triggers,
and improved logging and retry mechanisms
Explore new webhook event options, detailed setup, specific content triggers, and improved logging and retry mechanisms.
---

# Expanding Webhook Events

## Introduction

With Umbraco, you can create your own webhook events.
Umbraco developers can create their own webhook events.

This documentation guides you through the process of implementing your webhook events using the `WebhookEventBase<TNotification>` base class.
This article demonstrates the process of implementing custom webhook events using the `WebhookEventBase<TNotification>` base class.

## Creating an Event with the WebhookEventBase

The `WebhookEventBase<TNotification>` class serves as the foundation for creating custom webhook events. Here's a brief overview of its key components:

* **Alias**: The property that must be overridden to provide a unique identifier for your webhook event.
* **Alias**: The property that must be overridden to provide a unique identifier for the webhook event.
* **EventName**: A property that represents the name of the event. It is automatically set based on the provided alias unless explicitly specified.
* **EventType**: A property that categorizes the event type. It defaults to "Others" but can be customized using the `WebhookEventAttribute`.
* **WebhookSettings**: The property containing the current webhook settings.
Expand All @@ -38,14 +37,14 @@ To create a custom webhook event, follow these steps:
```
2. **Override the Alias Property**:

Provide a unique identifier for your event using the `Alias` property:
Provide a unique identifier for the event using the `Alias` property:

```csharp
public override string Alias => "YourUniqueAlias";
```
3. **Apply `WebhookEventAttribute` (Optional)**:

You can use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to your custom event class:
Use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to the custom event class:

```csharp
[WebhookEvent("Your Event Name", "YourEventType")]
Expand All @@ -55,13 +54,14 @@ To create a custom webhook event, follow these steps:
}
```

Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If you do not specify this attribute, the event name will default to your alias, and the type will default to `Other`.
Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If this attribute is not specified, the event name will default to the alias, and the type will default to `Other`.
4.
4. **Implement Notification Handling**:

If needed, customize the handling of the notification in the `HandleAsync` method.
5. **Register Your Webhook Event**:

Ensure that Umbraco is aware of your custom event by registering it in a composer:
Ensure that Umbraco is aware of the custom event by registering it in a composer:

```csharp
using Umbraco.Cms.Core.Composing;
Expand All @@ -74,11 +74,11 @@ To create a custom webhook event, follow these steps:
}
}
```
6. **Implement Optional Overrides**: Depending on your requirements, you can override methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` to customize the behavior of your webhook event.
6. **Implement Optional Overrides**: Depending on requirements, methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` can be overridden to customize the behavior of the webhook event.

### Sample Implementation

Here's a basic example of a custom webhook event:
The code below shows a sample implementation of a custom webhook event. The `YourCustomEvent` class is derived from the `WebhookEventBase<YourNotificationType>` class, and it overrides the `Alias` property to provide a unique identifier for the event. The `WebhookEventAttribute` is applied to the class to specify the event name and type.

```csharp
[WebhookEvent("Your Custom Event", "CustomEventType")]
Expand Down Expand Up @@ -111,7 +111,7 @@ public class YourCustomEvent : WebhookEventBase<YourNotificationType>

## Creating an Event with the WebhookEventContentBase\<TNotification, TEntity>

For scenarios where your webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase<TNotification, TEntity>`. This class is an extension of the generic `WebhookEventBase<TNotification>` and introduces content-related functionalities.
For scenarios where the webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase<TNotification, TEntity>`. This class is an extension of the generic `WebhookEventBase<TNotification>` and introduces content-related functionalities.

The `WebhookEventContentBase<TNotification, TEntity>` class is designed for content-specific webhook events, where `TEntity` is expected to be a type that implements the `IContentBase` interface.

Expand All @@ -131,23 +131,21 @@ To leverage the `WebhookEventContentBase<TNotification, TEntity>` class, follow
* **GetEntitiesFromNotification**: Implement this method to extract content entities from the notification.
* **ConvertEntityToRequestPayload**: Implement this method to customize the content entity payload before sending it to webhooks.

If we take a look at the `ContentPublishedWebhookEvent`, we can see how these methods are overridden.

{% include "../../.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md" %}
The `ContentPublishedWebhookEvent` class demonstrates how these methods are overridden.

```csharp
protected override IEnumerable<IContent> GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities;

protected override object? ConvertEntityToRequestPayload(IContent entity)
{
if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null)
{
return null;
}
var cachedPublishedContent = publishedContentCache.GetById(entity.Key);

IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key);
return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent);
}
return new
{
CustomData = "Your data",
PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent)
};
}
```

3. **ProcessWebhooks Implementation**:
Expand Down
Loading