0

I'm trying to create asana webhook through apex.

I keep failing the authentication phase - handshake:

{"errors":[{"message":"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'm missing some thing and not sure what.

I tried to create a class with @RestResource notation for handshake post callback:

@RestResource(urlMapping = '/AsanaWeb/*')
global class asanaCallbackCtrl {

public asanaCallbackCtrl(system.RestRequest req) {

}

@HttpPost
global static void doPost() {
    asanaCallbackCtrl ctrl = new asanaCallbackCtrl(RestContext.request); //asanaCallbackCtrl.newInstance(RestContext.request);
    RestResponse resp  = ctrl.executePost();
    RestContext.response.statusCode   = resp.statusCode;
    RestContext.response.responseBody = resp.responseBody;
   // the record not inserted to database..
   Log__c log = new Log__c();
    log.Body__c = JSON.serialize(resp.responseBody);
    log.Response_Hedears__c =  JSON.serialize(resp.headers);
    log.Staus_Code__c = string.valueOf(resp.statusCode);
    insert log;
}

public RestResponse executePost() {
    RestResponse  resp    = new RestResponse();
    RestResponse res = RestContext.response;


    try {
        Blob targetBlob = Blob.valueOf(res.headers.get('X-Hook-Secret'));
        // Generate SHA1 digest
        Blob hashSHA1 = Crypto.generateDigest('hmacSHA1', targetBlob);
        // For Rackspace Compatiblity encode the binary into BASE 64
        // this will result in 28 chars long string
        String hashBase64SHA1 = EncodingUtil.base64encode (hashSHA1);

        resp.addHeader('X-Hook-Secret', res.headers.get('X-Hook-Secret'));
        // verify the incoming request as legit; throw exception otherwise

        resp.statusCode = 200;
    }

    catch (Exception e) {
        resp.statusCode = 500;// set per doc (403 or 500)

    }

    // persist some log so you have a record of the incoming request
    return resp;
}

/**
 * Create a new task using Asana API
 */
public static HttpResponse createWebhook() {
    object resource = '486792005021811';

    string target = 'https://bringgsb-bringg.cs17.force.com/AsanaWeb/services/apexrest/AsanaWeb/486792005021811';
    NewWebhook newHook = new NewWebhook(resource, target);


    //NewTask newTask = new NewTask(new string[]{'139836167870950'}, '6125975198930', 'Lee Test Api', 'Test Notes');
    String JSONString = JSON.serialize(newHook);
    JSONString = '{"data":' + JSONString + '}';
    HttpResponse res;
    string base64Key = createAuthorizationHeader('0/859eb48d9719099d88cb2cfab4dbcb2e');
    /**
     * API call cannot be made while test class in running.
     * so setting the expected response on which code would run
     */
    if (Test.isRunningTest()) {

    } else {
        res = sendHttp(asanaEndPoint + '/webhooks', 'POST', JSONString  , 'Basic ' + base64Key);
    }
    return res;
}

}

I added this class to my site (Enable apex classes), but not sure if I put the correct url for my target: (i'm running in sandbox)

https://**[siteURL?]**/services/apexrest/**[domainName?]**/AsanaWeb/486792005021811
  • what is the status code? did you checl asana.com/developers/documentation/getting-started/errors, looks more like something you should check on the Asana Community – glls Nov 23 '17 at 16:07
  • Hi, I'm getting status code 400: No authorization, A valid API key was not provided with the request, so the API could not associate a user with the request. – Lee Khen Nov 26 '17 at 11:14
0

Setting up and debugging webhooks can be tricky

My example below is for Shopify but it may help you in your setup

Site (sandbox) definition:

http://sandboxName-myCompanyName.mysandboxPod.force.com/shopify

or, specifically

http://dev-foocompany.cs79.force.com/shopify  

The URL that you place into the webhook originator:

https://dev-foocompany.cs79.force.com/shopify/services/apexrest/shopify/neworder

The essence of the REST class is:

@RestResource(urlMapping='/shopify/*')
    global class ShopifyWebhookResponder
@HttpPost
    global static void doPost() {
      RestResponse resp  = ShopifyWebHookResponder.newInstance(RestContext.request).executePost();
      RestContext.response.statusCode   = resp.statusCode;
      RestContext.response.responseBody = resp.responseBody;
    }

    public RestResponse executePost() {
      RestResponse  resp    = new RestResponse();

      try {
        // verify the incoming request as legit; throw exception otherwise
        resp.responseBody = ... // process the body and build response 
        resp.statusCode = 200;
      }

      catch (Exception e) {
        resp.statusCode = // set per doc (403 or 500)
      }

      // persist some log so you have a record of the incoming request
      return resp;
}

The two keys are:

  • Return the correct HTTP statusCode per the doc of the webhook originator
  • Persist to a custom object Log__c (or use Platform Events) everything that happens to your webhook responder as you won't be able to use debug statements as there is no running user to trace.
  • Thank you for your reply.. I tried modify my code by your suggestion, but I still not reaching to "doPost".. can you explain: RestResponse resp = ShopifyWebHookResponder.newInstance(RestContext.request).executePost(); any suggestion? Thnks, Lee – Lee Khen Nov 26 '17 at 11:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.