Asana webhooks not firing / not being created

My web server has stopped receiving webhooks from Asana. I checked and my webhook was still active but I haven’t logged a webhook in 2 days. For reference I had been getting 100+ successful receipts every day. I attempted to delete and recreate my webhook this morning. While I was able to delete my webhook, suddenly I can not create a new one. I got the “Could not complete activation handshake with target URL. Please ensure that the receiving server is accepting connections and supports SSL”. My SSL seems to be active on the URL that receives the webhook - it says SECURE in my browser. At this point, I’m looking for something to try to troubleshoot.

For what its worth, I have used this target URL and it’s code for years so the fact that it stopped working indicates to me that something is lost in between Asana and my web server. Please help troubleshoot this if you have any ideas.

@Bastien_Siebman, @Diakoptis or @Matt_Bramlage any chance you can give @dannyramirez11 a hand?

Thanks I appreciate this! I may have exaggerated when I said years… but I have been using this target now since about March 2017.

1 Like

Here is my source code that acknowledges the creation of a webhook/accepts the payloads.

<?php
    $headers = getallheaders(); // This retrieves all header info which contains the X-Hook-Secret and Signature that we validate
    $timestarted = microtime(true); // This will get the end time of execution of the script (measured in microseconds)
    $hooktimestamp = date("d-M-Y h:i:s a"); 
    require ($_SERVER['DOCUMENT_ROOT'] . "/vanair/includes/connect.php");
    include ($_SERVER['DOCUMENT_ROOT'] . "/vanair/includes/functions.php");

    /*-- To confirm to Asana that this webhook is actively listening and functional, 
    they send out a test webhook while configuring the webhook initially and again periodically (once a day).
    This section must be kept in the script to confirm the existence of this page to Asana --*/

    if (!empty($headers['X-Hook-Secret'])) {
      $secret_token = $headers['X-Hook-Secret'];
      header('X-Hook-Secret: ' . $secret_token);
      header("HTTP/1.1 200 OK");
      $timeended = microtime(true); // This will get the end time of execution of the script (measured in microseconds)
      $timeelapsed = $timeended - $timestarted; // Total time to process the script
      $query = "INSERT INTO asanawebhooks (source, timestamp, timeelapsed, resource, status) VALUES ('secret', '$hooktimestamp', '$timeelapsed', '$secret_token', 'Closed')";
      $conn->query($query);
      exit;
      } 
      
      
    /*-- CHECK TO MAKE SURE X-HOOK-SIGNATURE IS PRESENT. 
    Asana will put this in the webhook so we can confirm it is Asana and not directly 
    being navigated to (intentionally or unintentionally).
    CURRENTLY NOT VALIDATING BUT SOON WOULD LIKE TO COMPARE TO SECRET TOKEN HASH --*/ 

    if (!empty($headers['X-Hook-Signature'])) {
      $signature_token = $headers['X-Hook-Signature'];

    //-- RETRIEVE CONTENTS OF THE WEBHOOK AND PREPARE IT FOR PROCESSING --//  
      $webhook = file_get_contents('php://input'); 

    //-- DEPOSIT THE PAYLOAD INTO OUR TABLE FOR OUR SYSTEM TO PROCESS --// 
      $query = "INSERT INTO asanawebhooks (source, timestamp, resource, contents, status) VALUES ('rdtest', '$hooktimestamp', '$signature_token', '$webhook', 'Not Started')";
      $conn->query($query);
      
    //-- REDIRECT TO LOCATION SPECIFIED BELOW FOR PROPER PROCESSING OF THE WEBHOOK --//
      header("HTTP/1.1 200 OK");               
      } 

    ?>

:thinking: that’s odd. I see that the webhook tried to deliver at around 12:05:15 UTC but failed with an unexpected failure. I also see that the error I get when I try to deliver it now is that its sync token has expired, meaning that it lost the context it needs to send the events you haven’t gotten yet - this could be the true cause for the unexpected failure. (for context, webhooks are more or less a proactive implementation on our events endpoint and maintain their own sync tokens that they use to ship out the events that are yet to be delivered).

I also tried to hit the callback endpoint for this webhook manually and everything looks fine, so I don’t expect that to be the issue. I don’t see that we had any production incidents at that time, so I wonder if there was something that was fixed with an automatic failover that seemed innocuous but in fact triggered this webhook to lose its sync token. (On a macro scale, it doesn’t look like we had a big spike in webhook failures at that time, so it would likely just be one of our webhook processor machines - lucky you! :confounded:)

Can you try recreating this webhook and seeing if you start getting events again? (This webhook was trashed because it failed in this way and won’t be able to recover)

1 Like

That’s part of this equation too. I did try to recreate a webhook and am getting an error now when I point to my target URL (or seemingly any target URL). Your token thought is very intriguing, though. It explains something I saw shortly before my webhooks stopped working.

Here is the code I use to create a new webhook. See anything crazy? I attempted to mask off personal stuff.

<?php
$apikey = "mytoken"; // Your personal access token

$data = array('target' => 'https://www.mywebsite.com/formhandlers/asanawebhook.php',
              'resource' => '160926033090015');

$headr = "Authorization: Bearer ". $apikey;
$curl = curl_init();
$options = array(CURLOPT_URL => 'https://app.asana.com/api/1.0/webhooks',
           CURLOPT_POST => TRUE,
           CURLOPT_POSTFIELDS => $data,
           CURLOPT_HTTPHEADER => array($headr),
           CURLOPT_RETURNTRANSFER => true
           );
curl_setopt_array($curl, $options);
$return = json_decode(curl_exec($curl), true);
curl_close($curl);

print_r($return);
?>

Ah, interesting. I don’t see any webhooks created since July 23rd, so I’m assuming that creation itself is failing. I suspect that there might be 2 things going on, then.

When you try to create the webhook and it fails, are you getting the message “Could not complete activation handshake with target url”?

1 Like

As a matter of fact, I am not getting that message. I am getting:

Could not complete activation handshake with target URL. Please ensure that the receiving server is accepting connections and supports SSL [help] => For more information on API status codes and how to handle them, read the docs on errors:
https://asana.com/developers/documentation/getting-started/errors

I checked with my web hosting and SSL seems to be working properly and I can send/receive things using other methods besides the Asana webhook. I have been using the same creation code for a year and every time I have ever needed to delete the webhook and recreate it I haven’t had a problem.

***Dan Ramirez
***Director of Engineering

1 Like

One more thing to add here. I have discovered that I can set up a Webhook through Zapier which is currently serving as an adequate workaround. But I can’t set one up through my web hosting service. Now I am beginning to wonder if I have something set up wrong in the handshake process.

Ah, yes, that is the error message I mean.

I suspect that the issue is that something has changed in your setup to make your code single-threaded. If you’re using a hosting service, you might not have even made this change yourself - it could be something that they did.

The ordering of the webhook handshake goes like this:

client                    server (Asana)
|----- POST /api/1.0/webhooks --->|
                                  |
   |<-- POST {your_target_url} -- |
   |                              |
   |--- 200 OK [with secret] ---> |
                                  |
|<----------- 200 OK -------------|

That is, the callback happens inside of the original request before the original request returns.

If:

  1. You post the webhook creation request from the same code that handles the handshake
  2. Your code is single-threaded (only has one thread in one running process)

Then your code will block on the original POST request for the duration of the whole handshake - that is, it’s waiting for the first request to return, and therefore it’s not available to handle the handshake which happens in the middle of the request.

If you’re not hosting this script yourself, I’m not sure what recourse you might have to handle this, unfortunately. One thing you could do is to use events to get much the same effect, but instead of having to have a publicly-available server ready to handle callbacks, you poll every so often to sync up with what’s changed in Asana. I hope this makes sense and you find a way to get to a resolution!

1 Like

hey :smiley: Sorry I was on summer vacations

Welcome back @Diakoptis :wave:t3:Hope you had a great holiday!