Ajax suggests that this code is being performed via a front end which means you are leaking your hub.secret to the world…
I imagine the Ajax call with conten-type application/json is trying to be clever and is converting the data to JSON before sending it. As you declared (via the header) that you wish to send JSON. (Content-Type says I’m sending this, Accept is I expect that)
Try body instead of data or pass the arguments/data (url encoded) via querystring instead of post body.
Javascript would infer node, node offers doing it raw or modules such as
request
axios
I prefer request myself
Since you are building an extension you can use any server language you want to build your EBS and capture webhook data. The Extension itself cannot receive the webhook data directly