Introduction

This resource covers:

What is a webhook?

A Webhook is a tool for retrieving and storing data from a certain event. They allow you to register an http:// or https:// URL where the event data can be stored in JSON or XML formats. For Shopify apps, webhooks are commonly used for:

  • Placing an order
  • Changing a product's price
  • Notifying your IM client or your pager when you are offline
  • Collecting data for data-warehousing
  • Integrating your accounting software
  • Filtering the order items and informing various shippers about the order
  • Removing customer data from your database when they uninstall your app

Another, less-obvious, case for using webhooks is when you're dealing with data that isn't easily searchable through the Shopify API. For example, re-requesting an entire product catalog or order history would benefit from using webhooks since it requires a lot of API requests and takes a lot of time.

Think of it this way, if you would otherwise have to poll for a substantial amount of data, you should be using webhooks.


Webhook events

Webhooks can be registered for the following events:

Cart
creation/update
Checkout
creation/deletion/update
Collection
creation/deletion/update
Customer group
creation/deletion/update
Customer
creation/deletion/disable/enable/update
Fulfillment
creation/update
Order
cancellation/creation/deletion/fulfillment/payment/update
Product
creation/deletion/update
Shop
update

View our Webhook API Reference guide.


Configure a webhook

You can configure your webhooks, one of two ways: through the API or through your store admin.

Configure a webhook through the API

The trouble with testing your webhooks through the API is that you need a publicly visible URL to handle them. Unlike client-side redirects, webhooks originate directly from the server. This means that you cannot use the following as an endpoint in your testing environment:

  • Localhost
  • Any URL ending in the word "internal" (i.e. thisshop.com/internal)
  • "Fake" domains like www.example.com
  • Shopify domains (i.e. shopify.com and myshopify.com)

Fortunately, there are a couple of tools that make working with webhooks during development much easier such as RequestBin, Pagekite and ngrok.

requestbin logo

RequestBin allows you to create a URL that will collect any requests made to it. You can then inspect your requests and see the values returned. The URL provided is temporary and can only be used for 20 requests or for 48 hours (whichever comes first).

pagekite logo

Pagekite makes local websites or SSH servers publicly accessible in mere seconds and works over any internet connection.

ngrok logo.

ngrok creates a tunnel from the public internet (http://subdomain.ngrok.com) to a port on your local machine. You can give this URL to anyone to allow them to try out a web site you're developing without doing any deployment.

View our Webhook API Reference guide.

Configure a webhook through your store admin

If you are developing an app for a particular shop, you can configure your webhooks through your shop admin. Go to the Settings > Notifications page and scroll down to the "Webhooks" section.

At the very bottom of the page click the Create a webhook button.

Select the event type you want to listen for from the drop-down box and enter the URL (http:// or https://) where you want to receive notifications.

After you create a webhook, Shopify lets you test your webhook notifications. In the list of order notifications you will see your webhook. You will also see a "send test notification" link. This "send test notification" link allows you to send an example order to the URL you provided.

If you want to capture the contents of a webhook to examine them, the easiest way is to set up a new subscription with a service like LocalTunnel, RequestBin or PostCatcher (described above) which will capture the result and let you view it in a browser.


Receive a webhook

Once you register a webhook URL with Shopify, we will issue a HTTP POST request to the URL specified every time that event occurs. The request's POST parameters will contain XML/JSON data relevant to the event that triggered the request.


Respond to a webhook

Your webhook acknowledges that it received data with a 200 OK response. Any response outside of the 200 range will let Shopify know that you did not receive your webhook. To this end, Shopify has implemented a 5-second timeout period and a retry period for subscriptions. We wait 5 seconds for a response to each request, and if there isn't one or we get an error, we retry the connection to a total of 19 times over the next 48 hours. A webhook will be deleted if there are 19 consecutive failures for the exact same webhook.

You should monitor your admin for failing webhooks. If you're receiving a Shopify webhook, the most important thing to do is respond quickly. There have been several historical occurrences of apps that do some lengthy processing when they receive a webhook that triggers the timeout. This has led to situations where webhooks were removed from functioning apps.

To make sure that apps don't accidentally run over the timeout limit, we now recommend that apps defer processing until after the response has been sent.


Verify a webhook created through the API

Webhooks created through the API by a Shopify App can be verified by calculating a digital signature.

Each Webhook request includes a X-Shopify-Hmac-SHA256 header which is generated using the app's shared secret, along with the data sent in the request.

Webhooks created manually through the Shopify admin cannot be verified using the following technique.

Requests from Webhooks not created via the API will not include this X-Shopify-Hmac-SHA256 header.

To verify that the request came from Shopify, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Shopify-Hmac-SHA256 header. If they match, you can be sure that the Webhook was sent from Shopify and the data has not been compromised.

Note that if you are using a Rack based framework such as Ruby on Rails or Sinatra the header you are looking for is HTTP_X_SHOPIFY_HMAC_SHA256

Below is a simple example in Ruby using the Sinatra web framework of how one might verify a webhook request.

require 'rubygems'
require 'base64'
require 'openssl'
require 'sinatra'

# The Shopify app's shared secret, viewable from the Partner dashboard
SHARED_SECRET = 'my_shared_secret'

helpers do
  # Compare the computed HMAC digest based on the shared secret and the request contents
  # to the reported HMAC in the headers
  def verify_webhook(data, hmac_header)
    digest  = OpenSSL::Digest::Digest.new('sha256')
    calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, SHARED_SECRET, data)).strip
    calculated_hmac == hmac_header
  end
end

# Respond to HTTP POST requests sent to this web service
post '/' do
  request.body.rewind
  data = request.body.read
  verified = verify_webhook(data, env["HTTP_X_SHOPIFY_HMAC_SHA256"])

  # Output 'true' or 'false'
  puts "Webhook verified: #{verified}"
end

And here's a PHP version:

<?php

define('SHOPIFY_APP_SECRET', 'my_shared_secret');

function verify_webhook($data, $hmac_header)
{
  $calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHOPIFY_APP_SECRET, true));
  return ($hmac_header == $calculated_hmac);
}


$hmac_header = $_SERVER['HTTP_X_SHOPIFY_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
error_log('Webhook verified: '.var_export($verified, true)); //check error.log to see the result

?>

What do I do if everything blows up?

Your hosting centre exploded and your app has been offline for more than 48 hours. It's back on its feet now, but you've missed a pile of data that was sent to you in the meantime. Not only that, but Shopify has cancelled your webhooks because you weren't responding for an extended period of time. How do you catch up? Let's tackle the problems in order of importance.

Getting your webhook subscriptions back should be straightforward as your app already has the code that registered them in the first place.One thing you should do is add a quick check that fetches all the existing webhooks and only registers the ones that you need. If you know for sure that they're gone you can just re-run that and you'll be good to go.

Importing the missing data is trickier. The best way to get it back is to build a harness that fetches data from the time period you were down for that feeds it into the webhook processing code one object at a time. The only caveat is that you'll need the processing code to be sufficiently decoupled from the request handlers that you can call it separately.

Ready to put what you've learned into action?

Build an online store with Shopify. Try it free.

Experience the future of retail now.

Shopify Point of Sale. Try it free.