# Add new webhooks and customize webhook payload

**URL:** https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609
**Category:** Administrators
**Tags:** webhooks, how-to
**Created:** [March 21, 2017, 10:27am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609 "2017-03-21T10:27:08Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [March 21, 2017, 10:27am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/1 "2017-03-21T10:27:08Z")

</div>

Ever wonder how to add new webhook types? Or how to reduce the payload? Here is the tutorial for the plugin authors. It demos how to add the session and user notification event types as well as customization to the payload. You can also check [the plugin on GitHub](https://github.com/fantasticfears/discourse-webhooks-example) while reading.

If you’d like to have a new webhook type supported by the team, bring up a feature request instead.

Before started, make sure you already understand [webhook guide](https://meta.discourse.org/t/setting-up-webhooks/49045).

## New webhook event type

A new webhook event type is defined in the database so that Ember client and webhook can find relevant information.

### 1.Seeding

Add a seed file in the following path of the plugin `db/fixtures/001_custom_web_hook.rb`.

```ruby
WebHookEventType.seed do |b|
  b.id = 100 # start with a relative large number so it doesn't conflict with the core type
  b.name = "notification"
end

WebHookEventType.seed do |b|
  b.id = 101
  b.name = "session"
end

```

Then putting `SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-webhooks-example", "db", "fixtures").to_s` into the plugin.

Admin dashboard needs the text to display the new event type. Adding them in `config/locales/client.<language-code>.yml`:

```yaml
en:
  admin_js:
    admin:
      web_hooks:
        notification_event:
          name: "Notification Event"
          details: "When there is a new notification."
        session_event:
          name: "Session Event"
          details: "When there is a login or logout."

```

### 2. Connect with the internal `DiscourseEvent` or hook on your own

```ruby
add_model_callback(:notification, :after_commit, on: :create) do
  # you can enqueue web hooks anywhere outside the AR transaction
  # provided that web hook event type exists
  WebHook.enqueue_hooks(:notification, # event type name
                        notification_id: self.id, # pass the relevant record id
                        # event name appears in the header of webhook payload
                        event_name: "notification_#{Notification.types[self.notification_type]}_created")
end

%i(user_logged_in user_logged_out).each do |event|
  DiscourseEvent.on(event) do |user|
    WebHook.enqueue_hooks(:session, user_id: user.id, event_name: event.to_s)
  end
end

```

### 3. Final step: Sidekiq Jobs

Adding a new method to the `Jobs::EmitWebHookEvent`:

```ruby
Jobs::EmitWebHookEvent.class_eval do
  # the method name should always be setup_<event type name>(args)
  def setup_notification(args)
    notification = Notification.find_by(id: args[:notification_id])
    return if notification.blank? # or raise an exception if you like

    # here you can define the serializer, you can also create a new serializer to prune the payload
    # See also: `WebHookPostSerializer`, `WebHookTopicViewSerializer`
    args[:payload] = NotificationSerializer.new(notification, scope: guardian, root: false).as_json
  end

  def setup_session(args)
    user = User.find_by(id: args[:user_id])
    return if user.blank?
    args[:payload] = UserSerializer.new(user, scope: guardian, root: false).as_json
  end
end

```

An aside note, the payload is sent as if you are an administrator browsing a Discourse site. Be careful for what you sent.

## Payload customization

There are two ways to reduce the payload size.

1. Define a custom serializer.
2. Uses plugin filter.

The first one is explicit to do. The second one involves a plugin API where you have the power to modify the payload. This enables the possibility to slice the JSON, i.e. @Lapinot [suggested](https://meta.discourse.org/t/webhooks-feedback/49046/2).

```ruby
Plugin::Filter.register(:after_build_web_hook_body) do |instance, body|
  if body[:session]
    body[:user_session] = body.delete :session
  end

  body # remember to return the object, otherwise the payload would be empty
end

```

Final aside note, a `{{plugin-outlet name="web-hook-fields"}}` is now available in the web hook configuration page.

The plugin code is available under [GitHub - erickguan/discourse-webhooks-example · GitHub](https://github.com/fantasticfears/discourse-webhooks-example).

Thanks @erlend_sh to encourage me writing this tutorial and @tgxworld for sorting out the internals.

---

<div class="post-metadata">

### Author: ![tgxworld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tgxworld/32/106117_2.png) [@tgxworld](https://meta.discourse.org/u/tgxworld)
#### Post date: [March 22, 2017, 3:22am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/2 "2017-03-22T03:22:10Z")

</div>

@fantasticfears Note that it isn’t recommended to run migrations in plugins. Instead I’ve updated the #howto to create a fixture file that will automatically be run when `db:migrate` is invoked.

---

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [March 22, 2017, 8:40am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/3 "2017-03-22T08:40:59Z")

</div>

Fixture is better than migration but [it doesn’t work](https://github.com/fantasticfears/discourse-webhooks-example/tree/fixture) with the plugin now. The plugin system includes only `db/migrate` but not fixture.

---

<div class="post-metadata">

### Author: ![tgxworld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tgxworld/32/106117_2.png) [@tgxworld](https://meta.discourse.org/u/tgxworld)
#### Post date: [March 22, 2017, 9:47am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/4 "2017-03-22T09:47:47Z")

</div>

Ah ha I forgot to include the secret sauce.

> <https://github.com/discourse/discourse-narrative-bot/blob/5ae7c8c7495bc5af667a6125b790e656b83d9b10/plugin.rb#L19>

---

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [March 22, 2017, 11:12am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/5 "2017-03-22T11:12:44Z")

</div>

![](https://global.discourse-cdn.com/meta/original/3X/6/0/6038490ef14fa55957284c8b265e24afa1384861.jpg)

I didn’t know there’s a new API `register_seedfu_fixtures`! Updated.

---

<div class="post-metadata">

### Author: ![Raja\_Ali](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/raja_ali/32/84196_2.png) [@Raja\_Ali](https://meta.discourse.org/u/Raja_Ali)
#### Post date: [October 21, 2018, 5:40pm UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/6 "2018-10-21T17:40:38Z")

</div>

what do i have to do to make it just notification webhook and remove the session event ?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [November 21, 2018, 5:47pm UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/7 "2018-11-21T17:47:10Z")

</div>

> [@fantasticfears](#):
>
> The first one is explicit to do. The second one involves a plugin API where you have the power to modify the payload. This enables the possibility to slice the JSON, i.e. @Lapinot [suggested](https://meta.discourse.org/t/webhooks-feedback/49046/2).

Can someone offer a hint here?

I need to submit this JSON payload when a new user is created:

```plaintext
{"email_address":"address of new user", "status": "subscribed"}

```

I guess I don’t know how to create a serializer.

---

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [November 21, 2018, 10:24pm UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/8 "2018-11-21T22:24:17Z")

</div>

> [@pfaffman](#):
>
> I guess I don’t know how to create a serializer.

This is easy.

```ruby
class MySerializer < ApplicationSerializer
  attributes :email_address, :status
end

my_object = MyClass.new(email_address: "address of new user", status: "subscribed")
MySerializer.new(my_object).as_json

```

---

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [November 22, 2018, 3:01am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/9 "2018-11-22T03:01:57Z")

</div>

@fantasticfears Thanks for the writeup!

It needs a bit of tweaking to take account of the changes introduced [in this commit](https://github.com/discourse/discourse/commit/bf84037f79ed8f2f5b5db0e22e2a17fbc7d38077#diff-0e98636b29e3b908201e344e101066ba).

- You no longer need a `setup_` method in `Jobs::EmitWebHookEvent`.

- There’s now a `WebHook` a class method for formatting custom payloads via a serializer:

Also, I’m wondering about the thinking behind namespacing the payload with the event type? This makes it a little harder to use endpoints you don’t fully control, which expect certain attributes in the body.

```plaintext
def build_web_hook_body(args, web_hook)
   ....
   if ping_event?(event_type)
     body[:ping] = 'OK'
   else
     body[event_type] = args[:payload]
   end
  ...
end

```

---

<div class="post-metadata">

### Author: ![fantasticfears](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/fantasticfears/32/119608_2.png) [@fantasticfears](https://meta.discourse.org/u/fantasticfears)
#### Post date: [November 22, 2018, 9:21am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/10 "2018-11-22T09:21:04Z")

</div>

Can you help me update the guide?

> [@angus](#):
>
> Also, I’m wondering about the thinking behind namespacing the payload with the event type? This makes it a little harder to use endpoints you don’t fully control, which expect certain attributes in the body.

This is mainly for possible extension. Additional information can be serialized to other keys. But we relies on serializers now so it’s more or less useless.

---

<div class="post-metadata">

### Author: ![luck7even](https://avatars.discourse-cdn.com/v4/letter/l/f9ae1b/32.png) [@luck7even](https://meta.discourse.org/u/luck7even)
#### Post date: [December 1, 2021, 9:17am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/11 "2021-12-01T09:17:49Z")

</div>

@fantasticfears  
Hi.

I’m trying to connect discourse to APP using webhooks.

I’ve done most of things but only one thing is left.

when you create a new topic in discourse, you send payload which has a lot of parameters to APP .

however, slack only get ‘text’ parameter. so I want to customize payload when using webhooks.

how do I change payload when using webhooks in discourse?

# AS-IS

```plaintext
{
  "post": {
    "id": 19,
    "name": "user",
    "username": "user",
    "avatar_template": "/letter_avatar_proxy/v2/letter/u/c0e974/{size}.png",
    "created_at": "2018-07-20T06:24:33.205Z",
    "cooked": "<p>Cool, now i have you, haha</p>",
    "post_number": 6,
    "post_type": 1,
    "updated_at": "2018-07-20T06:24:33.205Z",
    "reply_count": 0,
    "reply_to_post_number": null,
    "quote_count": 0,
    "avg_time": null,
    "incoming_link_count": 0,
    "reads": 0,
    "score": 0,
    "topic_id": 11,
    "topic_slug": "this-is-new-topic",
    "topic_title": "This is new topic",
    "display_username": "user",
    "primary_group_name": null,
    "version": 1,
    "user_title": null,
    "moderator": false,
    "admin": true,
    "staff": true,
    "user_id": 1,
    "hidden": false,
    "trust_level": 1,
    "deleted_at": null,
    "user_deleted": false,
    "edit_reason": null,
    "wiki": false,
    "topic_posts_count": 6
  }
}

```

# TO-BE

```plaintext
{
   "topic_title": "This is new topic"
}

```

Regard.

---

<div class="post-metadata">

### Author: ![gale](https://avatars.discourse-cdn.com/v4/letter/g/a9a28c/32.png) [@gale](https://meta.discourse.org/u/gale)
#### Post date: [January 2, 2022, 5:54pm UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/12 "2022-01-02T17:54:47Z")

</div>

Hi, I’m trying to create a custom webhook following this guide and sample plugin, but I can not get my new custom event types to show up in the webhook UI. I tried installing the plugin linked in this guide in my local dev instance and the events in this example plugin do not show up either. I’m guessing something changed between 2017 and now which affects this?

Does anyone here know how to get the example plugin in this topic to work? I _suspect_ the problem might be with the seeding code for the database since the new entries aren’t showing up in the `/admin/api/web_hooks` response. As it currently stands, this guide is not functional. Thanks!

---

<div class="post-metadata">

### Author: ![keff](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/keff/32/254412_2.png) [@keff](https://meta.discourse.org/u/keff)
#### Post date: [July 19, 2022, 10:26am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/13 "2022-07-19T10:26:10Z")

</div>

Hey there! I think I need some help

I’m attempting to add a custom webhook, which I’ve been able to get working and it correctly sends the payload to the webhook URL. The only thing I’m unable to accomplish is to be able to enable the event when configuring the webhook in admin. I’ve followed the tutorial above registering the fixture but it’s not appearing in admin.

I’ve tried a couple of ways:

```plaintext
SeedFu.fixture_paths << Rails.root.join("plugins", "<plugin_name>", "db", "fixtures").to_s
register_seedfu_fixtures(Rails.root.join("plugins", "<plugin_name>", "db", "fixtures").to_s)

```

Fixture:

```plaintext
WebHookEventType.seed do |b|
    b.id = 101
    b.name = "remove_like"
end

```

I also added this to locale:

```plaintext
en:
  js:
    plugin_name:
      placeholder: placeholder
    admin:
      web_hooks:
        remove_like_event:
          name: "Remove Like Event"
          details: "When a user marks a post as the accepted or unaccepted answer."

```

Am I missing something? or am I supposed to do it in some other way?

---

<div class="post-metadata">

### Author: ![keff](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/keff/32/254412_2.png) [@keff](https://meta.discourse.org/u/keff)
#### Post date: [July 19, 2022, 10:55am UTC](https://meta.discourse.org/t/add-new-webhooks-and-customize-webhook-payload/59609/14 "2022-07-19T10:55:46Z")

</div>

Okay, it seems to have been a cache issue or something, when I installed it in another instance of discourse it did appear.
