Confirming Webhook Authenticity

You should validate webhooks you receive from us to ensure:

  1. that it is from Constant Contact
  2. that the message content has remained unchanged 

Each Webhook request includes a special HTTP header named x-ctct-hmac-sha256 which is generated using the secret associated with the API key used by your application, along with the data sent in the request. You can find the secret for each API key you've registered in your Constant Contact developer account.

To verify that the request came from Constant Contact, compute the HMAC digest and compare it to the value in the x-ctct-hmac-sha256 header. If they match, you can be sure that the webhook was sent by Constant Contact and the message has not been compromised. We've provided Java and Ruby examples that use the API key secret and the message body to generate the HMAC digest for comparison.

Examples for creating the HMAC digest

Java HMAC digest example

String message = 
"{\"url\":\"https://api.constantcontact.com/v2/partner/accounts
/<accountId>/plan\",\"event_type\":\"tier.increase\"}";
String secret = "<API_key_secret>";
 
Mac macGenerator = Mac.getInstance("HmacSHA256"); SecretKeySpec encryptedKey = new SecretKeySpec(secret.getBytes(), "SHA-256");
try {
    macGenerator.init(encryptedKey);
}
    catch (InvalidKeyException e) {
    throw new IllegalStateException("Cannot initialize Mac Generator", e);
}
byte[] output = macGenerator.doFinal(message.getBytes());
return Base64.encodeBase64String(output);

Ruby HMAC digest example

data = "{\"url\":\"https://api.constantcontact.com/v2/partner/accounts/
<accountId>\\",\"event_type\",\"tier.increase\"}"
secret = "<API_key_secret>"
digest = OpenSSL::Digest.new('sha256')
calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, secret, data)).strip