Hello everyone, this is my first post.
Im trying to make my own bot for redeem points of my users, but Im not able to enable the subscription to the event, I set the data for the subscription and I receive the challenge, but when I send it back, its still pending of approval.
The three main functions to do it are:
const subscribeToEvent = () => {
const eventSubUrl = 'https://api.twitch.tv/helix/eventsub/subscriptions';
const payload = {
type: 'channel.channel_points_custom_reward_redemption.add',
version: '1',
condition: {
broadcaster_user_id: twitchChannelId, // ID del streamer
},
transport: {
method: 'webhook',
callback: twitchRedirectUrl + '/twitch-webhook', // URL de tu endpoint
secret: twitchSecret
}
};
fetch(eventSubUrl, {
method: 'POST',
headers: {
'Client-ID': twitchIdClient,
'Authorization': `Bearer ${twitchTokenDeApp}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
};
app.post('/twitch-webhook', (req, res) => {
console.log('twitch-webhook post', req.body)
if(req.body.challenge) {
const challenge = req.body.challenge
console.log('twitch-webhook challenge', challenge);
return res.status(200).send(challenge);
}
const signature = req.headers['twitch-eventsub-message-signature'];
const timestamp = req.headers['twitch-eventsub-message-timestamp'];
const hmacMessage = `${req.body}${timestamp}${JSON.stringify(req.body)}`;
const hmac = "sha256=" + createHmac("sha256", twitchSecret).update(hmacMessage).digest("hex");
// Verifica la firma
if (signature === hmac) {
const { event } = req.body;
// Procesa el evento de redeem
console.log('Evento de redeem:', event);
// Responde con un 200 para confirmar la recepción del evento
res.status(200).send('OK');
} else {
res.status(403).send('Forbidden');
}
});
app.listen(port, () => {
// Llamar a la función para conectar el WebSocket
console.log(`Servidor Express escuchando en http://localhost:${port}`);
subscribeToEvent()
});
The challenge is being sent back but its always pending, as I say in the title, the app is linked to ngrok. All other methods, like deleting subscriptions, work fine.
Thank you for reading me and I will be so grateful if you can help me.
That would suggest your ngrok URL changed and Twitch tried to verify the old one.
ngrok is fine for testing with but will change each time the ngrok tunnel restarts.
twitchRedirectUrl sounds like the variable name for your oAuth redirect rather than the URL for your webhook handler?
Depending on the production use case, might be better for you to be using websockets not webhooks?
Since if this bot is running on your local machine, websockets would be preferential than having ngrok in the mix.
This indicates that twitch could not call your callback URL and this will eventually flip over to one of the fail states, like the attempted verification failed attempts state whose name I don’t recal off hand.
Do you see NGROK logging an inbound call from Twitch?
Does your code see a inbound call from Twitch and not responding right?
Did you test your callback with the TwitchCLI to check it works as expected?
You likely need to be using encodeURIComponent here as well, if your you are seeing the console.log above it to indicate this code path is being reached.
Looking over your code theres plenty of “I wouldn’t do it like that” but theres nothing obviously wrong that would prevent this working.
First of all I get the static url of ngrok in the web, you can have one static domain and I used it on this. " ```twitchRedirectUrl" is the main static web address and then I put the rest of the path here:
callback: twitchRedirectUrl + '/twitch-webhook', // URL de tu endpoint
And the event reach ‘/twitch-webhook’ and I can even read the challenge, I send it back but I dont have any answer.
Depending on the production use case, might be better for you to be using websockets not webhooks?
Well I want to detect redeem rewards (one in specific) and do things in my api. How can I create a websocket in this situation?
Looking over your code theres plenty of “I wouldn’t do it like that” but theres nothing obviously wrong that would prevent this working.
Oh I would love to change it, but right now I dont know what I should change to do a better implementation.