Error with Events Webhook Callbacks

Hello, I have a somewhat complex problem. I’m trying to use the webhooks for channel points. The part to register the webhook works, the problem is in the callback part.

My problem is that I have a server in nodejs for the twitch bot and a server with apache2 and ssl to receive and send the verification, I leave the php code which I did to “send the verification”, I also leave the code that I use for " generate the webhook".

The problem is that it tells me “webhook_callback_verification_failed”, which I don’t know where the problem is because it doesn’t give me much info.

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
// Notification request headers
$TWITCH_MESSAGE_ID = 'Twitch-Eventsub-Message-Id';
$TWITCH_MESSAGE_TIMESTAMP = 'Twitch-Eventsub-Message-Timestamp';
$TWITCH_MESSAGE_SIGNATURE = 'Twitch-Eventsub-Message-Signature';
$MESSAGE_TYPE = 'Twitch-Eventsub-Message-Type';

// Notification message types
$MESSAGE_TYPE_VERIFICATION = 'webhook_callback_verification';

// Prepend this string to the HMAC that's created from the message
$HMAC_PREFIX = 'sha256=';

// Get the raw request body
$body = file_get_contents('php://input');

// Get the headers
$headers = array();
foreach ($_SERVER as $key => $value) {
  if (substr($key, 0, 5) === 'HTTP_') {
    $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))))] = $value;

// Get the secret
$secret = "aklsgfjhkalosghalshgaklsfjlasf";

// Build the message used to get the HMAC.
$message = $headers[$TWITCH_MESSAGE_ID] .

// Get the HMAC.
$hmac = $HMAC_PREFIX . hash_hmac('sha256', $message, $secret);

// Verify whether our hash matches the hash that Twitch passed in the header.
if (hash_equals($hmac, $headers[$TWITCH_MESSAGE_SIGNATURE])) {
  // Signatures match

    // TODO: Do something with the event's data.

    $notification = json_decode($body, true);

    // Log the notification to a file
    $log = sprintf("[%s] %s\n", date('Y-m-d H:i:s'), json_encode($notification, JSON_PRETTY_PRINT));
    file_put_contents('file.log', $log, FILE_APPEND);

    // Forward the notification to another link
    $ch = curl_init('');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

  } else if ($headers[$MESSAGE_TYPE] === $MESSAGE_TYPE_VERIFICATION) {
    echo $notification['challenge'];
  } else if ($headers[$MESSAGE_TYPE] === $MESSAGE_TYPE_REVOCATION) {
    // TODO: Handle revocation

  } else {
} else {
  // Signatures didn't match


AND here its code for makesub with nodejs , i use express for join link and tests.

app.get("/makesub", function (req, res) {
      { headers: { "Content-Type": "application/x-www-form-urlencoded" } }
    .then((response) => {
      var app_access_token =;
      var app_expires_in =;
      var app_token_type =;

      var postData = {
        type: "channel.channel_points_custom_reward_redemption.add",
        version: "1",
        condition: {
          broadcaster_user_id: broadcaster_id,
        transport: {
          method: "webhook",
          callback: "https://xxxxxxx/tw.php",
          secret: "aklsgfjhkalosghalshgaklsfjlasf",

      let axiosConfig = {
        headers: {
          "Client-ID": idcliente,
          Authorization: `Bearer ${app_access_token}`,
          "Content-Type": "application/json",

        .then((response) => {
        .catch((error) => {
    .catch((error) => {


a) you leaked your webhook secret in your code posted to the forum
2) Your nodeJS code is correct as it created hooks file, just verification failed
iii) The problem lies in your PHP code or the Apache hand off

You can test this using the Twitch CLI

I suspect the issue if you header loading, as off hand, I think PHP auto converts all header names to lowercase but you are trying to use CamelCased header names

here is a working example from my examples repository

ooooh , u save my life

thx for all <3

i gonna change secret not problem <3

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