Webhooks in Magento 2

hookThis post explores a short term approach for implementing a webhook in Magento 2. Better support for webhooks is on the backlog, but currently not guaranteed for Magento 2 GA.

So what is a webhook? Put simply, it is when software can be configured to send a HTTP request to a configurable destination (URL) when some event of interest occurs. For example, you might want a webhook called every time a new order is accepted from a customer – there may be an external system you want notified that the new order exists.

So why are webhooks hard to add to Magento? Magento has always had the concept of events, so has a logical place for webhooks to integrate with.

The first issue is more that you would really prefer webhook calls to be performed asynchronously so they do not slow down the main processing flow. You don’t want your PHP code to block because of a slow external URL. This post does not address this issue.

Another issue is events are frequently passed classes. To send data to a remote end point, the relevant data from the class needs to be serialized into some data structure like JSON or XML which is then POSTed to the configured URL. So some serialization code is required. It would be nice if that was configurable, but for this post good old PHP will be used.

So next I thought “great, I will go implement a sample module that implements a webhook by registering an observer that sends a HTTP request to a remote end point”. I thought this could be a useful example to create. Being a good software engineer, my first job was to find some good code to copy and adjust.

The file I picked was the Observer.php file in the Magento_CacheInvalidate module. It was an observer implementation that was fairly short, there was an events.xml file, there was a reference to curl, … hang on!

You guessed it, the Magento_CacheInvalidate module actually only contains one thing – an observer implementing a webhook notify an external URL when to flush its cache! So much for my grand plans to implement a new sample webhook module.

So how does it work?

  • First, there is an events.xml file in the etc directory binding various events to functions in the Observer class.
  • Next, if you look at the Observer constructor you will see a reference to \Magento\Framework\HTTP\Adapter\Curl. The dependency injection framework will provide this instance to your observer for talking to the PHP curl library (a HTTP client library built into PHP).
  • If you look invalidateVarnish() you will see example code that extracts information from the event to form the data to send to Varnish. It calls sendPurgeRequest() which puts the string into a HTTP header field. This could be easily adjusted to generate a JSON or XML payload instead.
  • The flushAllCache() function is even simpler. It shows an example of sending a webhook call where nothing is extracted from the event.

This particular example includes a bit of custom logic – there are configuration settings that are used to see if Varnish is enabled that is not required for a normal webhook. The invalidateVarnish() function also joins a few strings to form the correct Varnish header string.

So let’s see how short a webhook could be. I took the flushAllCache() function and stripped all comments and unneeded data structures. Obviously you should not do this in real life, but it helps show the complexity of the code required. I also removed the Varnish specific ‘if enabled’ check. Finally, I made the constructor get the URL from the di.xml file. As you can see, not much code is required to implement a web hook. You do need to add code to extract data from the event if you want to send that data to the end point, but it’s pretty easy to do with PHP with its built in JSON and XML support.

namespace Magento\CacheInvalidate\Model;

class Observer
    protected $url;
    protected $curlAdapter;

     * Constructor
     * @param string $url
     * @param \Magento\Framework\HTTP\Adapter\Curl $curlAdapter
    public function __construct(
        \Magento\Framework\HTTP\Adapter\Curl $curlAdapter
    ) {
        $this->url = $url;
        $this->curlAdapter = $curlAdapter;

    public function flushAllCache(\Magento\Framework\Event\Observer $observer)
        $headers = ["X-Magento-Tags-Pattern: .*"];
        $this->curlAdapter->setOptions([CURLOPT_CUSTOMREQUEST => 'PURGE']);
        $this->curlAdapter->write('', $this->url, '1.1', $headers);

So that is it! My sample webhook without actually needing to write one. A sample that is built in by default to every installation.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: