Webhook Callback URL not recieving Challenge

So I’ve been trying to get a Webhook for subscribing to an event when a streamer gains a follower. I’m able to get Status Code 202 from the initial POST request. I’m not able to get the Subscription Verify Request from twitch to my callback URL. The callback URL is able to receive GET requests. The Client-ID works with many other api requests I’ve used.

I’ve looked at quite a few other’s codes, and multiple forums, haven’t had any success. If anyone would be able to give my code a glance it would be much appreciated!

var request = require('request');
async function hook(){
      return new Promise(function(resolve, reject) {
           let hub = [
                `hub.mode=subscribe`, // subscribe
                `hub.callback=https://thehighlighthub.com/SubscribeTwitch`, // this is the url where I 
                          receive the GET and POST from twitch
               `hub.lease_seconds=864000`, // 864000
               "hub.topic=https://api.twitch.tv/helix/users/follows?to_id=29795919" // stream online 
                             topic = https://api.twitch.tv/helix/streams?user_id=44322889
                  ].join('&')

 request(({ method: 'POST', json: true, url: 'https://api.twitch.tv/helix/webhooks/hub?' + 
            hub, headers: {'Client-ID': '************',
                         'Content-Type': 'application/json'}}),
         (err, res, body) => {
                   err && reject('webhooks failed')
                   console.log(body)
                   resolve(res.toJSON().statusCode === 202 ? 'webhook connected' : 
                   res.toJSON().statusCode + ' Error: ' + body.message)
    })
  })
}
 hook()

Edit: Tidied code.

The code you have posted, is the code that creates a Webhook request, which you say you are getting a 202 so it is working successfully.

Where is your code handling your inbound callback requests?

You should have code that opens expects a HTTP GET to your callback of https://thehighlighthub.com/SubscribeTwitch that looks for a query string argument of hub.challenge and just echo that out with a 200 status code

Woops, should’ve posted that as well, I appreciate your time for responding.

 app.get('/SubscribeTwitch*',(request, response) => {
  console.log(request.query['hub.topic']);
  console.log(request.params)
  console.log(request.query)
  var challenge = request.query['hub.challenge'];
  console.log(challenge);
   response.set({
        'Access-Control-Allow-Origin': '*',
        'x-timestamp': Date.now(),
        'x-sent': true
    })

  response.status(200).send(challenge);
});

Right now I’m just trying to print out anything that comes through. I’m able to send a GET request through XMLRequest Browser with response 200. Plugging URL into browser with params works fine too.

Are you seeing a

In your log when you get the 202 on your POST? The request should be fairly instant.

The only other real difference between mine and yours in Node/JS is that I use

app.get(‘/webhook/’, function(req, res) {

instead.

And I just do

res.send(req.query[‘hub.challenge’]);

Rather than an explicit .status(200)

Thanks again for the reply.

Within few milliseconds I see the 202 from the POST. I have yet to see the GET request to my callback URL.

On sending my own artificial GET requests to the callback URL, I can of course emulate the proper fields. The problem is not receiving a GET request from twitch in the first place after the initial POST.

So to answer your question explicitly,

No, due to twitch not sending a GET request in response to the initial POST.

The GET handler of the callback URL can be fiddled with if need be when something comes from twitch.

I’m taking a stab in the dark here, but try to url encode the hub.callback and hub.topic values.

Also, the docs say that the first parameter must be provided in the hub.topic and it’s value must be 1.

also try

request(({ method: ‘POST’, url: ‘https://api.twitch.tv/helix/webhooks/hub?’ +
hub, headers: {‘Client-ID’: ‘************’}),

Cross checking your call with my call.

In case it’s 202-ing where it ought not to

Also to avoid fun™ with encoding:

https://dev.twitch.tv/docs/api/webhooks-reference/#example-of-webhook-flow

Suggests:

curl -H ‘Client-ID: uo6dggojyb8d6soh92zknwmi5ej1q2’
-H ‘Content-Type: application/json’
-X POST -d ‘{“hub.mode”:“subscribe”,
“hub.topic”:“https://api.twitch.tv/helix/users/follows?to_id=1337”,
“hub.callback”:“https://yourwebsite.com/path/to/callback/handler”,
“hub.lease_seconds”:“864000”,
“hub.secret”: s3cRe7}’
https://api.twitch.tv/helix/webhooks/hub

So:

request({method: "POST’, url: ‘https://api.twitch.tv/helix/webhooks/hub’, json: true, body: {“hub.mode”:“subscribe”,
“hub.topic”:“https://api.twitch.tv/helix/users/follows?first=1&to_id=1337”,
“hub.callback”:“https://yourwebsite.com/path/to/callback/handler”,
“hub.lease_seconds”:“864000”,
“hub.secret”: s3cRe7}, headers: { Client-ID: ‘xxxxx’ }

Should do the trick, not tested off the top of my head™

Funny you bring up that example, as I’ve tried using it, and ended up keeping their hub.topic for later testing.

Seems like trumpi27 found an error, it even gives 202 with that call.

I’ll show updated code, eliminated URL encoding problems, good suggestion.

var request = require('request');
async function hook(){
      return new Promise(function(resolve, reject) {
   					
var A =JSON.stringify({"hub.mode":"subscribe",
"hub.topic":"https://api.twitch.tv/helix/users/follows?first=1&to_id=1337",
"hub.callback":"https://www.thehighlighthub.com/SubscribeTwitch",
"hub.lease_seconds":"864000","hub.secret": "s3cRe7"})

       request(({ method: 'POST',  url: 'https://api.twitch.tv/helix/webhooks/hub?',body: A, 
headers: {'Client-ID': '***********',"Content-Type":"application/json"}}),
         (err, res, body) => {
          err && reject('webhooks failed')
          console.log(body)
	      console.log(JSON.stringify(res));
          resolve(res.toJSON().statusCode === 202 ? 'webhook connected' : res.toJSON().statusCode + ' Error: ' + body.message)
    })
  })
}
hook()

Only difference from your Curl-To-Node JS Requests translation is, instead of json:true in the request argument, the “Content-Type”:“application/json” header was added. Would get status code 400 otherwise. Also changed the hub.topic value to accomodate their required notation.

Edit: Adding the response I’m getting,

{"statusCode":202,"body":"","headers":{"content-length":"0","server":"nginx","access-control-allow- 
origin":"*","cache-control":"no-cache, no-store, must-revalidate, 
 private","expires":"0","pragma":"no-cache","ratelimit-limit":"30","ratelimit- 
remaining":"29","ratelimit- 
  reset":"1530147305","twitch-trace-id":"cb0285c532e52e3b0f06451555d0f96c","x-ctxlog- 
 logid":"1- 5b3431b0-7b985420fbc32fac9f8a4cf0","timing-allow origin":"https://www.twitch.tv","date":"Thu, 28 Jun 2018 00:54:08 GMT","connection":"close"},"request":{"uri"{"protocol":"https:","slashes":true,"auth":null,"host":"api.twitch.tv","port":443,"hostname":"api.twitch.tv","hash":null,"search":"?","query":"","pathname":"/helix/webhooks/hub","path":"/helix/webhooks/hub?","href":"https://api.twitch.tv/helix/webhooks/hub?"},"method":"POST","headers":{"Client-ID":"***********","Content-Type":"application/json","content-length":211}}}

From Mobile Posting

Heh. That’s what happens when I write sample code and not test it whilst flying a spaceship

From the nodeJS request docs:

body - entity body for PATCH, POST and PUT requests. Must be a Buffer, String or ReadStream. If json is true, then body must be a JSON-serializable object.

And there is a hiccup in my sample post

I think the original problem was that you sent everything in the query string and send a header of content type JSON. And then didn’t send any JSON. And then Twitch API sent a 202 anyway

Excuse mistakes I’m on mobile

Updates at a computer:

request({method: "POST’, url: ‘https://api.twitch.tv/helix/webhooks/hub’, json: true, body: {“hub.mode”:“subscribe”,
“hub.topic”:“https://api.twitch.tv/helix/users/follows?first=1&to_id=1337”,
“hub.callback”:“https://yourwebsite.com/path/to/callback/handler”,
“hub.lease_seconds”:“864000”,
“hub.secret”: “s3cRe7”}, headers: { Client-ID: ‘xxxxx’ }

I omitted the " around s3cRe7

json - sets body to JSON representation of value and adds Content-type: application/json header. Additionally, parses the response body as JSON.

So the header should be optional but no harm setting it expliciciciciltly

is correct however

       let hub = [
            `hub.mode=subscribe`, // subscribe
            `hub.callback=https://thehighlighthub.com/SubscribeTwitch`, // this is the url where I 
                      receive the GET and POST from twitch
           `hub.lease_seconds=864000`, // 864000
           "hub.topic=https://api.twitch.tv/helix/users/follows?to_id=29795919" // stream online 
                         topic = https://api.twitch.tv/helix/streams?user_id=44322889
              ].join('&')

request(({ method: ‘POST’, json: true, url: ‘https://api.twitch.tv/helix/webhooks/hub?’ +
hub, headers: {‘Client-ID’: ‘************’,
‘Content-Type’: ‘application/json’}}),

Is not, because you say HEY I AM POSTING and then set the Content/Body to JSON and then send a JSON/body length of zero. So, HEY I AM POSTING SOME JSON IN THE BODY THE JSON IS ''

A common hiccup with API’s you do one thing and say another with your headers.

  • Content-Type - sets the type of data you are sending, in this case you sent nothing
  • Accept - sets the type of data you are expecting and/or type hints to the cURL handler what do do with the response (auto parse a JSON string to a object for example)

Hope this ramble helps :slight_smile:

I appreciate the post, clears up some communication that’s been happening.

I’ve went ahead and added this, still getting 202 with no request to the callback URL. I’ve now tried different Client ID, made new App on different Twitch account, tried different IP addresses, varied the topics each time.

I’ve also changed hub back into object form and set it equal to the requests body parameter (As the docs do say JSON Body parameter for this api), set json:true to stringify it. Still 202 with no request to callback URL. If you can think of any other failure tests I could check on my end I’d appreciate it.

I believe just the fact I’m able to successfully send GET requests to my callback URL, and that my POSTS are getting 202’s, yet not requests to the callback URL from Twitch, implies that Twitch’s API is faulty.

Again, thanks for the help.

That would seem unlikely as my code is basically the same as your code and I’m not having an issue with WebHooks across three servers each with different combinations of topics, and callback URL’s

You could open up your server NGINX (assuming NGINX) access/error logs and check for the call from Twitch coming in and raising an error that doesn’t make it to node, or coming in on a route that your Node Express server isn’t binding a response on

If you have something like Cloudflare in front of your server that could be conflicting also

It’s a pure Node Express HTTPS server. I have middleware that alerts when ANY request is made across the domain. I’m able to do Oauth authentication, various other api requests from Twitch, so it’d be hard to believe the GET request sending the challenege would somehow be the only thing filtered out.

It would be nice if they sent something other than 202 if their GET challenge request wasn’t received properly. I’m using webhooks fine on other services such as Paypal and Discord currently with the same server.

Using this code:

const request = require('request');

let hub = [
        `hub.mode=subscribe`, // subscribe
        `hub.callback=http://todaytest.proxy.beeceptor.com`,
       `hub.lease_seconds=10`, // 864000
       "hub.topic=https://api.twitch.tv/helix/users/follows?to_id=29795919" // stream online
          ].join('&')

request(
{ method: 'POST', json: true, url: 'https://api.twitch.tv/helix/webhooks/hub?' +

hub, headers: {'Client-ID': 'MYCLIENTID',

'Content-Type': 'application/json'}},

function(e,r,b) {
console.log(r.statusCode);
});

Posting to TwitchAPI and sending requests to a mock/capture bin located at

The result is a 202 for the console.log(r.statusCode); and in the bin:

Node v8.11.2
Request v2.87.0

I cannot find a issue with my code, or the code you have presented which indicates the problem is with Twitch and not with you.

Also rip http://requestb.in/ my preferred bin :frowning:

Edit: for completeness:

let hub = [
    `hub.mode=subscribe`, // subscribe
    `hub.callback=http://todaytest.proxy.beeceptor.com/somefolder`,
   `hub.lease_seconds=10`, // 864000
   "hub.topic=https://api.twitch.tv/helix/users/follows?to_id=29795919" // stream online
      ].join('&')

Yep got the challenge right away. Good to know about another debug tool, I appreciate this information.

Just tried above code on bare https server(same domain I’ve been using), no challenge GET request.

I’m able to send GET requests to the callback URL just fine, so I’m stumped. Might just create a new minimal cloud server, forward the domain there, and see if there’s a different result. Going to try a few more things, I’ll update soon.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.