Webhooks

Webhooks enable Help Scout to call a script on your server when one or more events have happened. Webhooks can be thought of as event listeners or push notifications.

Configuring webhooks can be done through the Help Scout user interface. Simply login, click on Apps in the top header bar, then select the Webhooks app.

Available Events

Type Event Name Request Header Request Body
Conversation Assigned convo.assigned Conversation object
Created convo.created Conversation object
Deleted convo.deleted {id: id-of-convo-that-was-deleted}
Merged convo.merged Conversation object
Moved convo.moved Conversation object
Status Updated convo.status Conversation object
Tags Updated convo.tags Conversation object
Customer Reply convo.customer.reply.created Conversation object
Agent Reply convo.agent.reply.created Conversation object
Note Created convo.note.created Conversation object
Customer Customer Created customer.created Customer object
Ratings Rating Received satisfaction.ratings Rating object

Headers

Each webhook includes two headers:

  • X-HelpScout-Event: Lists the event name for which this webhook event is being generated
  • X-HelpScout-Signature: The computed signature generated by Help Scout. Used to know if the request is valid or not.

Verifying

Webhooks can be verified as coming from Help Scout by calculating a digital signature. Each webhook request contains an X-HelpScout-Signature header, which is generated using the given secret key, along with the json encoded payload data sent in the request.

To verify if the request came from Help Scout, compute the HMAC hash and compare it to the header value sent in the request. If the computed signatures match, you can be sure the request was sent from Help Scout.

PHP

<?php
define('WEBHOOK_SECRET_KEY', 'my-secret-key');

function isFromHelpScout($data, $signature) {
	$calculated = base64_encode(hash_hmac('sha1', $data, WEBHOOK_SECRET_KEY, true));
	return $signature == $calculated;
}

$signature = $_SERVER['X-HELPSCOUT-SIGNATURE'];
$data = file_get_contents('php://input');
if (isFromHelpScout($data, $signature)) {
	// do something
}
?>

When using the Help Scout PHP library, this validation is automatically handled for you.

Ruby

Thanks to our friends at Parse.com for the Ruby example below:

#!/usr/bin/ruby -rrubygems
#
require 'base64'
require 'hmac-sha1' # gem install ruby-hmac

WEBHOOK_SECRET_KEY = "your secret key"

# Returns true if the webhook request is verified to have come from Help Scout.
#
# data       String  The data posted by Help Scout to the webhook.
# signature  String  Value for the http-x-helpscout-signature header.
#
def is_from_help_scout(data, signature)
  hmac = HMAC::SHA1.new(WEBHOOK_SECRET_KEY)
  hmac.update(data)
  Base64.encode64("#{hmac.digest}").strip == signature.strip
end

# Usage Example
signature = "+oNIxipGoqx4t2BmkBHbXKc6VHM="
data = '{"ticket":{"id":"1","number":"2"},"customer":{"id":"1","fname":"Jackie","lname":"Chan","email":"jackie.chan@somewhere.com","emails":["jackie.chan@somewhere.com"]}}'

puts "This request came from Help Scout:"
puts is_from_help_scout(data, signature)

And an updated ruby example using openssl (instead of hmac-sha1):

#!/usr/bin/ruby -rrubygems

require 'openssl'
require 'base64'

WEBHOOK_SECRET_KEY = "your secret key"

def is_from_help_scout?(data, signature)
  return false if data.nil? || signature.nil?
  hmac = OpenSSL::HMAC.digest('sha1', WEBHOOK_SECRET_KEY, data)
  Base64.encode64(hmac).strip == signature.strip
end

def helpscout_signature(data)
  hmac = OpenSSL::HMAC.digest('sha1', WEBHOOK_SECRET_KEY, data)
  Base64.encode64(hmac.strip)
end

data = '{"ticket":{"id":"1","number":"2"},"customer":{"id":"1","fname":"Jackie","lname":"Chan","email":"jackie.chan@somewhere.com","emails":["jackie.chan@somewhere.com"]}}'
signature = helpscout_signature(data)

puts "This request came from Help Scout:"
puts is_from_help_scout?(data, signature)

Node.js:

Thanks to one of our Help Scout customers for the following Node.js example.

/*jshint node: true */
'use strict';

var crypto = require('crypto'),
config = require('../lib/config').config;

module.exports = function(secret) {
    return function(req, res, next) {
        req.isHelpScout = false;
	
        var hsSignature = req.header('X-HelpScout-Signature');
        if (hsSignature) {
            req.hsHasher = crypto.createHmac('sha1', secret);
            req.on('data', function (chunk) {
                req.hsHasher.update(chunk);
            });
            req.on('end', function() {
                var hash = req.hsHasher.digest('base64');
                req.isHelpScout = hash === hsSignature ? true : false;
            });
        }
        next();
    };
};

Java

A java example can be found in the Webhook.java class in the Help Scout Java library.

Responses

Anything returned in the body of the response will be discarded. In order to know the webhook was successful, an HTTP status code of 200 must be returned.

Any status code other than 200 is a failure of some kind. A failed event is retried up to 10 times (with an increasing timeout period in between each retry). If the event fails all 10 retries, it is discarded.

Webhooks are automatically deactivated if three or more events get discarded.

API Clients

The supported API clients have functionality included to facilitate working with webhooks.