Managing Your Craft Inventory Using Snipcart Webhooks

Keeping your Craft inventory updated with Snipcart Webhooks

Editor's note: since publishing this post, we've released built-in inventory management for Snipcart. :)

In order to understand this post, we highly suggest you read a previous blog post we wrote last year: Integrating Snipcart with Craft CMS: A Child's Play!.

By default, Snipcart does not have inventory management features. But our customers usually use a CMS such as Craft, which already contains all their product information. And all we need to do to manage an inventory is update the product quantity when a new order is placed. So, to allow our users to do so, we developed Webhooks that will call your application through a HTTP POST request once a new order has been placed on your website.

In this post we will show you how to handle the order.completed event to update your Craft entries when someone buys a product on your website.

Adding the quantity field to your entry

You will need to create a new field which will contain your product quantity. In Craft admin, go to Fields section and hit New field:

Quantity field

Adding the field to your entry type

The next step will be to add the field to your existing entry type. Go to Sections and click on Edit entry types:

Edit entry types

Then drag the field into the entry type:

Drag entry type

Once you've done this, you can click on Entries, click on your product and insert a value in the quantity field:


Creating the plugin

We will need to create a Craft plugin in order to catch the Webhook request. Why? Because we don't want to alter Craft's code base and we also want to isolate the code that is related to Snipcart.

The first step will be to define the plugin under the craft/plugins folder and to create a SnipcartWebhookPlugin.php file. This file will make the plugin discoverable by Craft.

<!-- lang: php -->


namespace Craft;

class SnipcartWebhooksPlugin extends BasePlugin {
  public function getName() {
    return Craft::t('Snipcart Webhooks');

  public function getVersion() {
    return '0.1';

  public function getDeveloper() {
    return 'Snipcart';

  public function getDeveloperUrl() {
    return '';

The plugin will consist of a simple controller that will handle the HTTP request. Start by creating a controllers folder in which you'll create a new PHP file named SnipcartWebhooks_WebhookController.php.

Now we'll create the controller:

<!-- lang: php -->


namespace Craft;

class SnipcartWebhooks_WebhooksController extends BaseController {

In order to make it work, we will have to allow anonymous requests on this controller (by default, it will only respond to authenticated requests). To do so we must add the following line in the controller:

<!-- lang: php -->

protected $allowAnonymous = true; 

Then we will define an action that will actually handle the POT request.

<!-- lang: php -->

public function actionHandle() {

The action methods must be prefixed by action.

This method will read the request body and handle the order.completed event.

<!-- lang: php -->

public function actionHandle() {

    $json = craft()->request->getRawBody();
    $body = json_decode($json, true);

    if (is_null($body) or !isset($body['eventName'])) {

    switch ($body['eventName']) {
        case 'order.completed':
            // We handle the order.completed event.
            $this->returnBadRequest(array('reason' => 'Unsupported event'));

If the body does not contain an eventName, we will want to return a 400 Bad Request response. I made a simple method to return this response you can easily add to the controller.

<!-- lang: php -->

private function returnBadRequest($errors = array()) {
    header('HTTP/1.1 400 Bad Request');
    $this->returnJson(array('success' => false, 'errors' => $errors));

The next step will be to read the request body and update quantity for each product that has been purchased. The processOrderCompletedEvent method will do it.

<!-- lang: php -->

private function processOrderCompletedEvent($data) {
    $content = $data['content'];
    $updated = array();
    // We must iterated on each item
    foreach ($content['items'] as $item) {
        // We update the item quantity
        $entry = $this->updateItemQuantity($item);

        if ($entry != null) {
            $updated[] = $entry;


<!-- lang: php -->

private function updateItemQuantity($item) {
    // We are using Craft Entries service to retrieve and update items
    $service = craft()->entries;

    $entry = $service->getEntryById($item['id']);

    if ($entry != null) {
        $attrs = $entry->getContent();

        $newQuantity = $attrs['quantity'] - $item['quantity'];

            'quantity' => $newQuantity


        return $entry;
    } else {
        return null;

The code above will iterate through the items of the order that have been completed and update each entries in the Craft database.

Installing the plugin

If you don't want to write all the code, you can simply install the plugin by cloning our Github repository.

In the craft/plugins folder, just clone our repository or your fork.

<!-- lang: sh -->
git clone snipcartwebhooks

Then, open your browser and go to Craft admin. Next, hit the Plugins section, where you will see snipcartwebhooks in the available plugins. Click on install:

Craft plugins

Enter your webhook URL

Now login to your Snipcart dashboard, go to Settings > Webhooks and enter the URL.

The URL you'll enter should look like this: http://{}/actions/snipcartWebhooks/webhooks/handle

If you want to know why you must use this URL, take a look at Craft Plugin development documentation about Controllers.

Snipcart webhooks

Set product maximum quantity

The last step will be to use quantity value and set a max quantity on the product. By doing so, customers won't be able to add products that you do not have in stock to their cart.

In the blog post about integrating Snipcart into Craft, we created a template to list the product details in which we included the Snipcart markup that defines the product. Now we'll need to add a new attribute in it.

<!-- lang: html -->

{% extends "_layout" %}
{% set title = "Store" %}

{% block content %}

    {% for entry in craft.entries.section('store').find() %}
                {{ entry.title }}

               <!-- Render Snipcart buy button -->
              <a href="#"
                 data-item-price="{{ entry.price }}"
                 data-item-id="{{ }}"
                 data-item-name="{{ entry.title }}"
                 data-item-description="{{ entry.description }}"
                 data-item-max-quantity="{{ entry.quantity }}"
                 data-item-url="{{ url('store') }}">
                 Buy it
    {% endfor %}
{% endblock %}

Here we added the data-item-max-quantity and used the entry quantity field.

Testing it

You are now ready to test your hook! Just make a new order on your Craft website, and once it's completed, Snipcart will make the HTTP call to your application. In the Snipcart admin dashboard, you'll be able to see the history of each call. Login into the dashboard, go to Settings > Webhooks and you should see a successfull call:

Snipcart webhooks history

Finally, you can also go to your Craft admin > Product details and you will see that the quantity has been decremented.

You can find the source code of the plugin on Github. Feel free to comment below or hit us up if you have any questions regarding Craft integration and inventory management!

Suggested posts: