Creating notifications via the API

AI-generated summary

The discussion revolves around creating notifications via Discourse’s API. Mevo initiates the conversation, asking if notifications can be sent through the API, noting the lack of a POST endpoint in the documentation. pfaffman suggests a plugin might be necessary, while renato shares plans for a similar plugin and provides code references for creating custom notifications. blake reveals an undocumented API endpoint for creating notifications using the custom type, which can be used with data to pass relevant information. pfaffman experiments with the API but finds that clicking the notification doesn’t work, highlighting that the message field must be an I18n key. renato explains how to override the url in a custom widget to handle redirection. ootwch encounters a data can't be blank error, which Arkshine clarifies is due to the data field needing to be JSON-encoded.

Hi, a quick question: Can you send notifications to users with the API? (or another way).
In the documentation, I found how to GET notifications of the user, how to mark them as read, but not how to POST some. If it isn’t possible, I guess there is always to possibility of using private messages instead.
I would appreciate any input on this. Thanks.

I think it would take a plugin. What kind of notification do you want? Can you describe your use case?

Typically, replacing the email notifications from an external service with Discourse notifications. The service would be provided for free to members (*). This would allow to centralize everything towards Discourse, and to give an incentive to log (regularly) to the forum. That was the idea I had in mind. I’m not sure if it makes sense or not, or if there are flaws in the reasoning. I’m open to every suggestion / criticism.

[ (*): Members = forum participants. At least people registered to the forum. Remains to be seen if there is a minimum participation or trust level required, or if registering is enough. ]

The plugin would receive the information and trigger notifications in Discourse? Notifications can be (more easily) done from a plugin?

I can imagine a plugin that added a route and you could push a load with the user id (or email address), a url, and a title that would create a notification. I don’t think that you could do it without a plugin, but I’ve not looked that closely at the code.

I just yesterday started to consider adding notifications to a plugin that I’m developing,so I’m not that familiar with how it works.

I’m planning a similar plugin myself, centering my website non-email notifications around Discourse, which you can then subscribe to via MessageBus and have a central push notification configuration.

What I’m planning is just having a custom endpoint for creating custom notifications, after seeing these snippets I think it’s feasible.

For creating a custom notification:

For customizing how the notification item is displayed on the notification list:
https://github.com/discourse/discourse-code-review/blob/master/assets/javascripts/discourse/widgets/code-review-commit-approved-notification-item.js.es6

If there were a core API for creating the notification, I think this notification item widget could be done on a theme component, which would be even simpler.

I don’t know how potentially more complicated it may be to do, but wouldn’t it make sense to add notifications creation directly to the API? Maybe the team would be open to do this, or be open to a PR (if someone can and is willing to do this)?

It’s not documented yet, but there is a create notification api endpoint:

 POST /notifications(.:format) notifications#create {:format=>/(json|html|\*\/\*)/}

You might be able to use the custom notification type instead of having to create your own.

That’s great! Thank you.

So, if I understand it correctly, with the endpoint, if there’s a need for overriding DefaultNotificationItem then a plugin would still be needed just to register the additional notification type to be used in a custom widget?

Notification.types[:following] = 800

(from discourse-follow/plugin.rb at main · discourse/discourse-follow · GitHub)

Using the custom type it will be rendered using https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/app/widgets/custom-notification-item.js, so for overriding the destination url a custom widget would still be needed?

I saw one plugin overriding “custom-notification-item” in a similar scenario, is it safe to just override url when there’s something specific on data and fallback to
this._super.url otherwise?

Thanks, @renato!

Here’s what I’ve got.

Notification.create!(
  notification_type: Notification.types[:custom],
  user_id: 1,
  topic_id: nil,
  post_number: nil,
  high_priority: true,
  data: {
    message: 'pfaffmanager.title',
    display_username: 'pfaffman',
    topic_title: 'my title'
  }.to_json
)

I see the notication, but, predictably, (EDIT:) NOTHING happens if I click. Also (not obvious to me until I did it), the message is a I18n, not an arbitrary string. . . ). What I’d like is to be able to put the URL to the model that called it.

I suppose you meant “nothing” happens?
If you could click it and be redirected to an URL you joined through the API, that would be amazing, indeed.

The DefaultNotificationItem creates a url automatically if you fill data.badge_id, topic_id or data.group_id.

I tested this approach and it works. Just fill data.url and use this in a theme component:

  api.reopenWidget("custom-notification-item", {
      url(data) {
          return data.url || this._super(data);
      }
  })

I don’t get this to work…

POST https://XXX/notifications
Api-Key:XXX
Api-Username:system
Content-Type:application/json
Accept:application/json

{
    "notification_type":9,
    "user_id": 123,
    "post_number": 1,
    "topic_id": 956,
    "data": {
        "topic_title": "Test",
        "original_post_id": 2222,
        "original_post_type": 1,
        "original_username": "User.Name",
        "revision_number": 1,
        "display_username": "Text"
            }

}

I get as response:


{
  "errors": [
    "Data can't be blank"
  ],
  "error_type": "record_invalid"
}

Formatting error, misunderstanding? Or am I missing something in data?

I can’t really reverse engineer this from the web - Or is this API called somewhere?

You need to encode the data value.

e.g.:

"data": "{\"topic_title\":\"Test\",\"original_post_id\":2222,\"original_post_type\":1,\"original_username\":\"User.Name\",\"revision_number\":1,\"display_username\":\"Text\"}"