guides / Webhook
Emmanuel avatar

Emmanuel

Examples

Create your endpoint


The first thing to do, is to create an API with an endpoint accepting POST requests.
In this example, we will be using Node.js and Expressjs.

$ mkdir webhook-api
$ cd webhook-api
$ npm init -y
$ npm install --save express

Then, create a small HTTP server:

// index.js

const express = require('express')
const crypto = require('crypto')

// Constants declarations
const PORT = 8080
const KEY = 'PbjuWrm83Z7ZkflrSWyfEd0yz4Dygmk3' // The same key to set-up later in the dashboard
const ALGO = 'sha256'

const app = express()

// Enable Express to use JSON data format
app.use(express.json())

// Declare your endpoint: POST http://localhost:8080/webhook
app.post('/webhook', (req, res) => {
  // Get the "challenge" value from the request's body
  const { challenge } = req.body

  // Get the signature of the request from the request's headers
  const signature = req.headers['x-hub-signature']

  // Now let's generate the HMAC SHA256 Hex digest of the
  // challenge to verify the authenticity of the request
  const hash = crypto
    .createHmac(ALGO, KEY)
    .update(challenge)
    .digest('hex')

  // Now check the integrity
  if (hash !== signature) {
    // Do something with the integrity failure
  }

  // Now get the full notification data
  const notification = req.body

  // Do stuff with the received notification payload

  // Now let's build the response to send to Bodyguard
  const response = { challenge }

  // And send it back
  res
    .header('Content-Type', 'application/json')
    .send(response)
})

// Run your tiny API
app.listen(PORT, () => console.log(`Webhook example API running on port ${PORT}`))

Then, simply run your API:

$ node index.js
Webhook example API running on port 8080

Expose your endpoint on the Internet

Now that we have our tiny API running and waiting for incoming notifications, it HAS to be accessible from the Internet and through HTTPS protocol.

The following steps are ONLY meant for DEVELOPMENT purpose. Do NOT do that in production.

To expose your endpoint as required, you can use NGROK: See NGROK documentation for installation steps.


Once installed and set up correctly, simply run this command:

$ ngrok http 8080
ngrok by @inconshreveable                                                                                                                                                                                                     (Ctrl+C to quit)

Session Status                online
Account                       <your_ngrok_registered@email.address> (Plan: Free)
Version                       2.3.40
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://ede9-109-2-22-27.ngrok.io -> http://localhost:8080
Forwarding                    https://ede9-109-2-22-27.ngrok.io -> http://localhost:8080

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

You are not forced to run this command from your project directory, it will work from anywhere, unless your port 8080 is aleady in use.

As we can see here, NGROK deployed 2 temporary Internet-accessible endpoints that tunnel toward your locally running API:


http://ede9-109-2-22-27.ngrok.io and https://ede9-109-2-22-27.ngrok.io


As said above, we will ONLY send notification through HTTPS connections, so we will use the second one for the next steps.

Endpoint testing


Before being able to register and use your Webhook, a testing process has to be performed in order to make sure that everything is well-configured and ready to use.


So, when you finished entering the informations about your Webhook on the Dashboard, click Test integration button to manually launch the testing process.


It will simply send an HTTP POST request to the Webhook URL you provided, with this simple payload:

{
    "challenge": "7cbe2b6a0a5e58934bc3c5ea77be7de6de77e633a1432f0e1883584d135045cd"
}

See the Challenge section for more informations about the response to send.

Simply back the Challenge as requested in the Challenge section, and the testing process will be validated.


If you do not send the expected response, the testing process will fail and you will NOT be able to register and use your Webhook.

MessageUpdated payload

{
    "version": 1,
    "organization": {
        "id": "5d849494-2b0e-49fc-85d5-7197ca62d7fe",
        "name": "Bodyguard"
    },
    "time": 1630940073706,
    "eventType": "MESSAGE_UPDATED",
    "challenge": "54cddd8ead45bb5661ce229ca67b674e576b959f596851428c4f711724b9cb95",
    "messageUpdatedData": {
        "previousMessage": {
            "resourceType": "TEXT",
            "type": "HATEFUL",
            "classifications": [
                "BODY_SHAMING",
                "INSULT"
            ],
            "publicationDate": "2021-06-11T03:42:00.420Z",
            "directedAt": "SINGLE_PERSON",
            "recommendedAction": "KEEP",
            "severity": "HIGH",
            "text": "lol",
            "reference": "bodyguard/6d0f43f2-5058-4cf1-869f-14a6a52a8b4b"
        },
        "newMessage": {
            "resourceType": "TEXT",
            "type": "HATEFUL",
            "classifications": [
                "BODY_SHAMING",
                "INSULT"
            ],
            "publicationDate": "2021-06-11T03:42:00.420Z",
            "directedAt": "SINGLE_PERSON",
            "recommendedAction": "REMOVE",
            "severity": "HIGH",
            "text": "lol",
            "reference": "bodyguard/6d0f43f2-5058-4cf1-869f-14a6a52a8b4b"
        },
        "channelId": "cbc601f1-dec6-4594-9476-51628a17499a",
        "sourceId": "81310ae5-228e-438e-9720-35f737b9ca9f"
    }
}

PostUpdated payload

{
    "version": 1,
    "organization": {
        "id": "5d849494-2b0e-49fc-85d5-7197ca62d7fe",
        "name": "Bodyguard"
    },
    "time": 1630940073706,
    "eventType": "CONTENT_UPDATED",
    "challenge": "54cddd8ead45bb5661ce229ca67b674e576b959f596851428c4f711724b9cb95",
    "contentUpdatedData": {
        "previousContent": {
            "permalink": "https://link.to.post",
            "title": "Hey check this out",
            "type": "VIDEO",
            "status": "PUBLISHED",
            "identifier": "post-1234-abcd"
        },
        "newContent": {
            "permalink": "https://link.to.post",
            "title": "Hey check this out",
            "type": "VIDEO",
            "status": "REMOVED",
            "identifier": "post-1234-abcd"
        },
        "sourceId": "81310ae5-228e-438e-9720-35f737b9ca9f"
    }
}

AuthorUpdated payload

{
    "version": 1,
    "organization": {
        "id": "5d849494-2b0e-49fc-85d5-7197ca62d7fe",
        "name": "Bodyguard"
    },
    "time": 1630940073706,
    "eventType": "AUTHOR_UPDATED",
    "challenge": "54cddd8ead45bb5661ce229ca67b674e576b959f596851428c4f711724b9cb95",
    "authorUpdatedData": {
        "previousAuthor": {
            "birthdate": "1989-10-19T00:00:00.000Z",
            "gender": "MALE",
            "permalink": "https://link.to.profile",
            "status": "ACTIVE",
            "identifier": "user/1a2b3c4d"
        },
        "newAuthor": {
            "birthdate": "1989-10-19T00:00:00.000Z",
            "gender": "MALE",
            "permalink": "https://link.to.profile",
            "status": "BANNED",
            "identifier": "user/1a2b3c4d"
        },
        "sourceId": "81310ae5-228e-438e-9720-35f737b9ca9f"
    }
}