Managing webhooks notifications

The webhooks notification is a POST request with a JSON body and contains the following fields:

There are two webhooks sections: webhooks for development and webhooks for production. The former is for testing on development setup, while the latter is for use with your app once it has been released to production. Make sure to configure both appropriately. For sandbox, webhooks fire near real time. For production, developers can configure for how long Intuit should aggregate events for their application to 1 Minute, 3 Minutes, and 5 Minutes.

Note

There are no Intuit-imposed limits to either payload size or number of events. However, individual server architectures may impose their own limits (2MB is a common default size limit). You should assume this limit is imposed by your server unless you are certain it is otherwise.

Sample payload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
   "eventNotifications":[
   {
      "realmId":"1185883450",
      "dataChangeEvent":
      {
         "entities":[
         {
            "name":"Customer",
            "id":"1",
            "operation":"Create",
            "lastUpdated":"2015-10-05T14:42:19-0700"
         },
         {
            "name":"Vendor",
            "id":"1",
            "operation":"Create",
            "lastUpdated":"2015-10-05T14:42:19-0700"
         }]
      }
   }]
}

Note

Although the notification is designed to accommodate multiple RealmIDs, it only uses one at this time. If your app is connected to multiple companies, you will receive multiple eventNotifications (one per RealmID).

Validating the notification

Once you configure a webhooks endpoint, Intuit provides an app-specific Verifier Token. You can view this by clicking Show Token after webhooks creation.

Use this token to validate the notification received upon callback.

qbo/docs/develop/webhooks/Screen_Shot_2016-07-06_at_10.37.00_AM.png

Using the Verifier token

The verifier token allows you to ensure that the webhooks notification actually comes from Intuit. To do so:

  1. Hash the notification payload with HMAC_SHA256_ALGORITHM using<verifier token> as the key.
  2. Convert the intuit-signature header from base-64 to base-16.
  3. Compare the value from step 1 to theintuit-signatureheader from the notification. The values should be identical.

Sample Header

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
content-length:262
intuit-created-time:2016-02-02T16:25:00-0800
intuit-t-id:9cf50b60-8b0e-4fea-8327-e6a66099fe6f
proxy-connection:keep-alive
host:sample-endpoint.ilb.idg-notify-ppd.a.intuit.com:8443
intuit-notification-schema-version:0.1
content-type:application/json; charset=utf-8
intuit-signature:6kQBQtjwjupelRMwkyJsnpq80uhz2o+Rn92+m03GhKE=
accept:application/json
user-agent:intuit_notification_server/0.1

Sample signature verification (Java)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;

public class VerifySignatureExample {
   private static final String SIGNATURE = "intuit-signature";
   private static final String ALGORITHM = "HmacSHA256";
   public boolean isRequestValid(Map<String, String> headers, String payload, String verifier) {
      String signature = headers.get(SIGNATURE);
      if (signature == null) {
         return false;
      }
      try {
         SecretKeySpec secretKey = new SecretKeySpec(verifier.getBytes("UTF-8"), ALGORITHM);
         Mac mac = Mac.getInstance(ALGORITHM);
         mac.init(secretKey);
         String hash = Base64.getEncoder().encodeToString(mac.doFinal(payload.getBytes()));
         return hash.equals(signature);
      } catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException e) {
         return false;
      }
   }
}