Scoped Webhooks #4790

Open
opened 2026-02-05 09:15:50 +03:00 by OVERLORD · 2 comments
Owner

Originally created by @DanielGordonIT on GitHub (May 21, 2024).

Describe the feature you'd like

The ability to bind a webhook in scope to either a single book or shelf (and all child books), or multiple books or shelves (and all child books), instead of being global.

This is really only applicable to certain classes of actions, like _create, _update, _move, _delete, the comment events. The event types checked below could feasibly be scoped, the unchecked ones are global by default pretty much.
image

Describe the benefits this would bring to existing BookStack users

This allows more granularity and for better control. In my use case, I don't ever need a webhook to tell me if ANY page has been edited, but I do have needs to know if pages in specific books are edited. Different books are scoped to different teams, but creating a webhook to update specific teams about which pages in their books are updated is difficult, as webhooks see everything. The current webhook implementation is good if everything is global, and there is only one main team (which is supposed to see everything).

Can the goal of this request already be achieved via other means?

Technically, yes. I posted a solution in #5009 that allows you to lock a specific webhook to only fire correctly (it'll still try to send the webhook, but with malformed output and will fail safely. Probably, anyway.) given a specific book ID and webhook name combo.

<?php

use BookStack\Activity\Models\Loggable;
use BookStack\Activity\Models\Webhook;
use BookStack\Activity\Tools\WebhookFormatter;
use BookStack\Facades\Theme;
use BookStack\Theming\ThemeEvents;
use BookStack\Users\Models\User;

function selectiveFormat(array $defaultWebhookData): array
{
    $book_id = $defaultWebhookData['related_item']['book_id'];
    $webhook_name = $defaultWebhookData['webhook_name']
    if ( !(
        ($book_id == 1 && $webhook_name == "Team 1 Webhook") ||
        ($book_id == 2 && $webhook_name == "Team 2 Webhook") ||
        ($book_id == 3 && $webhook_name == "Team 3 Webhook") ||
        ($book_id == 4 && $webhook_name == "Team 4 Webhook")
    )
    ) {
        // If it's a teams webhook, but the name and book ID don't match, then just return nothing and cause a 400 error.
        return [];
    }
    return null;

}

Theme::listen(ThemeEvents::WEBHOOK_CALL_BEFORE, function (
    string $event,
    Webhook $webhook,
    string|Loggable $detail,
    User $initiator,
    int $initTime,
) {
    if (str_starts_with($webhook->endpoint, 'https://teams.webhook.whatever')) {
        $defaultData = WebhookFormatter::getDefault($event, $webhook, $detail, $initiator, $initTime);
        return selectiveFormat($defaultData->format());
    }
    return null;
});

This is adapted from https://www.bookstackapp.com/hacks/pushover-webhooks/.

Have you searched for an existing open/closed issue?

  • I have searched for existing issues and none cover my fundamental request

How long have you been using BookStack?

3 months to 1 year

Additional context

No response

Originally created by @DanielGordonIT on GitHub (May 21, 2024). ### Describe the feature you'd like The ability to bind a webhook in scope to either a single book or shelf (and all child books), or multiple books or shelves (and all child books), instead of being global. This is really only applicable to certain classes of actions, like _create, _update, _move, _delete, the comment events. The event types checked below could feasibly be scoped, the unchecked ones are global by default pretty much. ![image](https://github.com/BookStackApp/BookStack/assets/108084596/f1cfb3d7-0e14-410c-8257-c9ef5de73627) ### Describe the benefits this would bring to existing BookStack users This allows more granularity and for better control. In my use case, I don't ever need a webhook to tell me if ANY page has been edited, but I do have needs to know if pages in specific books are edited. Different books are scoped to different teams, but creating a webhook to update specific teams about which pages in their books are updated is difficult, as webhooks see everything. The current webhook implementation is good if everything is global, and there is only one main team (which is supposed to see everything). ### Can the goal of this request already be achieved via other means? Technically, yes. I posted a solution in #5009 that allows you to lock a specific webhook to only fire correctly (it'll still try to send the webhook, but with malformed output and will fail safely. Probably, anyway.) given a specific book ID and webhook name combo. ```php <?php use BookStack\Activity\Models\Loggable; use BookStack\Activity\Models\Webhook; use BookStack\Activity\Tools\WebhookFormatter; use BookStack\Facades\Theme; use BookStack\Theming\ThemeEvents; use BookStack\Users\Models\User; function selectiveFormat(array $defaultWebhookData): array { $book_id = $defaultWebhookData['related_item']['book_id']; $webhook_name = $defaultWebhookData['webhook_name'] if ( !( ($book_id == 1 && $webhook_name == "Team 1 Webhook") || ($book_id == 2 && $webhook_name == "Team 2 Webhook") || ($book_id == 3 && $webhook_name == "Team 3 Webhook") || ($book_id == 4 && $webhook_name == "Team 4 Webhook") ) ) { // If it's a teams webhook, but the name and book ID don't match, then just return nothing and cause a 400 error. return []; } return null; } Theme::listen(ThemeEvents::WEBHOOK_CALL_BEFORE, function ( string $event, Webhook $webhook, string|Loggable $detail, User $initiator, int $initTime, ) { if (str_starts_with($webhook->endpoint, 'https://teams.webhook.whatever')) { $defaultData = WebhookFormatter::getDefault($event, $webhook, $detail, $initiator, $initTime); return selectiveFormat($defaultData->format()); } return null; }); ``` This is adapted from https://www.bookstackapp.com/hacks/pushover-webhooks/. ### Have you searched for an existing open/closed issue? - [X] I have searched for existing issues and none cover my fundamental request ### How long have you been using BookStack? 3 months to 1 year ### Additional context _No response_
OVERLORD added the 🔨 Feature Request label 2026-02-05 09:15:50 +03:00
Author
Owner

@PascalLeroi commented on GitHub (Aug 5, 2024):

This would be pretty much perfect for specific updates in channels that only are interested in certain topics :)

@PascalLeroi commented on GitHub (Aug 5, 2024): This would be pretty much perfect for specific updates in channels that only are interested in certain topics :)
Author
Owner

@Lumrenion commented on GitHub (Aug 28, 2024):

Users can watch books, chapters and pages, which is implemented really well. So I as a user can be notified via email when a page inside a specific book was updated. A similar behaviour for webhooks would be very powerful, so I as an admin can send a notification to e.g. a specific Zulip/Slack/Discord channel when Book A was updated, and to a different channel when Book B was updated.

@Lumrenion commented on GitHub (Aug 28, 2024): Users can watch books, chapters and pages, which is implemented really well. So I as a user can be notified via email when a page inside a specific book was updated. A similar behaviour for webhooks would be very powerful, so I as an admin can send a notification to e.g. a specific Zulip/Slack/Discord channel when **Book A** was updated, and to a different channel when **Book B** was updated.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/BookStack#4790