Using the Spiffy Ajax API

From Spiffy Stores Knowledge Base

You can access the Spiffy Ajax API from your theme to enhance your customers' experience on your store.

The Spiffy Ajax API allows your customer to add items to the cart, update quantities in the cart and fetch information about the cart, all without requiring a page refresh. You can use the API to create 'add to cart' buttons that keep the customer on the product pages.

The Spiffy Ajax API also allows you to directly fetch information about a particular product using its handle.

Simple Access using the Wrapper Library

If you are using the jQuery JavaScript framework in your theme, then you can use the Spiffy Ajax API wrapper library to simplify the use of the API.

Of course, it's not necessary to use the wrapper library, or to code in jQuery to use the Ajax API, but if you do use the wrapper library, then a lot of the detailed API access work has already been done for you.

To use the Spiffy Ajax API jQuery wrapper library, you will need to include the following code in your theme.liquid file.

{{ 'jquery.js' | global_asset_url | script_tag }}
{{ 'api.jquery.js' | global_asset_url | script_tag }}

Wrapper Library Function Reference

Utility Functions

Spiffy.formatMoney(price, format)

Returns a formatted string, given a numberic price and optional format string.

The price is the floating-point value in the base unit of currency. For example, the price 1234.45 would be formatted as $1,234.56 using the default format.

The format string can include any characters, along with a substitution variable with the following values:

  • amount - Default formatting for the currency
  • amount_no_decimals - Uses only the base currency unit
  • amount_with_comma_separator - Uses a comma to specify the decimals
  • amount_no_decimals_with_comma_separator - Uses a comma decimal separator

For example, the default format string is

'${{amount}}'

Spiffy.onError(XMLHttpRequest, textStatus)

Spiffy.onCartUpdate(cart)

Spiffy.onItemAdded(line_item)

Spiffy.onProduct(product)

Spiffy.resizeImage(image, size)

Ajax Calls

Spiffy.addItem(variant_id, quantity, callback)

Spiffy.addItemFromForm(form_id, callback)

Spiffy.getCart(callback)

Spiffy.getProduct(handle, callback)

Spiffy.changeItem(variant_id, quantity, callback)

Spiffy.changeItemIndex(cart_index, quantity, callback)

Spiffy.removeItem(variant_id, callback)

Spiffy.removeItemIndex(cart_index, callback)

Spiffy.clear(callback)

Spiffy.updateCart(updates, callback)

Spiffy.updateCartFromForm(form_id, callback)

Spiffy.updateCartAttributes(attributes, callback)

Spiffy.updateCartNote(note, callback)

Spiffy Ajax API Reference

GET /products/<product-handle>.js

Retrieve a product using the product handle and return the results as a JSON representation of the product.

Example:

{
  "id": 3121506,
  "title": "T-Shirt",
  "handle": "t-shirt",
  "url": "/products/t-shirt",
  "description": "<p>Featuring distressed edges & short sleeves.</p>",
  "created_at": "2008-07-16T08:25:09+10:00",
  "updated_at": "2015-06-24T14:04:58+10:00",
  "vendor": "Spiffy Stores",
  "type": "T-Shirts",
  "tags": [
    "clothing",
    "t-shirt"
  ],
  "price": "16.30",
  "price_max": "19.45",
  "price_min": "16.30",
  "available": true,
  "price_varies": true,
  "compare_at_price": "0.00",
  "compare_at_price_max": "12.59",
  "compare_at_price_min": "0.00",
  "compare_at_price_varies": true,
  "images": [
    {
      "id": 1840,
      "product_id": 3121506,
      "type": "Product",
      "position": 1,
      "alt": "",
      "src": "http://mystore.spiffystores.com/sites/1/products/1506_limet_000_full.jpg"
    },
    {
      "id": 1841,
      "product_id": 3121506,
      "type": "Product",
      "position": 2,
      "alt": "",
      "src": "http://mystore.spiffystores.com/sites/1/products/1506_tealt_000_full.jpg"
    }
  ],
  "featured_image": {
    "id": 1840,
    "product_id": 3121506,
    "type": "Product",
    "position": 1,
    "alt": "",
    "src": "http://mystore.spiffystores.com/sites/1/products/1506_limet_000_full.jpg"
  },
  "options": [
    "Size",
    "Colour",
    "Thread Colour"
  ],
  "option_values": [
    [
      "S",
      "M",
      "L",
      "XL",
      "XXL",
      "XXXL"
    ],
    [
      "Orange",
      "Green",
      "Purple",
      "Red"
    ],
    [
      "Teal",
      "Yellow"
    ]
  ],
  "option_combos": [
    [
      "0.0",
      "Teal"
    ],
    [
      "0.6297373387",
      "Yellow"
    ]
  ],
  "variant_option_index": 2,
  "variants": [
    {
      "id": "1691_0",
      "title": "S/Orange Teal",
      "price": "16.30",
      "compare_at_price": "0.00",
      "discount": "0.00",
      "available": true,
      "inventory": true,
      "inventory_quantity": 10,
      "inventory_management": "spiffy",
      "inventory_policy": "deny",
      "weight": 100,
      "sku": "SHIRT002",
      "barcode": "",
      "requires_shipping": true,
      "taxable": true,
      "free_shipping": false,
      "ship_separately": false,
      "option1": "S",
      "option2": "Orange",
      "option3": null,
      "options_id": 0
    },
    {
      "id": "1691_1",
      "title": "S/Orange Yellow",
      "price": "16.69",
      "compare_at_price": "0.00",
      "discount": "0.00",
      "available": true,
      "inventory": true,
      "inventory_quantity": 10,
      "inventory_management": "spiffy",
      "inventory_policy": "deny",
      "weight": 100,
      "sku": "SHIRT002",
      "barcode": "",
      "requires_shipping": true,
      "taxable": true,
      "free_shipping": false,
      "ship_separately": false,
      "option1": "S",
      "option2": "Orange",
      "option3": null,
      "options_id": 1
    },
    {
      "id": "1690_0",
      "title": "M/Green Teal",
      "price": "16.61",
      "compare_at_price": "0.00",
      "discount": "0.00",
      "available": true,
      "inventory": true,
      "inventory_quantity": 93,
      "inventory_management": "spiffy",
      "inventory_policy": "deny",
      "weight": 100,
      "sku": "SHIRT001",
      "barcode": "",
      "requires_shipping": true,
      "taxable": true,
      "free_shipping": false,
      "ship_separately": false,
      "option1": "M",
      "option2": "Green",
      "option3": null,
      "options_id": 0
    },
    
...
    {
      "id": "2137_1",
      "title": "XXXL/Orange Yellow",
      "price": "19.84",
      "compare_at_price": "12.59",
      "discount": "0.00",
      "available": true,
      "inventory": true,
      "inventory_quantity": 20,
      "inventory_management": "spiffy",
      "inventory_policy": "deny",
      "weight": 0,
      "sku": "SHIRT007",
      "barcode": "",
      "requires_shipping": true,
      "taxable": true,
      "free_shipping": false,
      "ship_separately": false,
      "option1": "XXXL",
      "option2": "Orange",
      "option3": null,
      "options_id": 1
    }
  ],
  "exchange_rate": 0.6297373387,
  "currency": "GBP"
}

Example call using jQuery:

jQuery.getJSON('/products/t-shirt.js', function(product) {
  alert('The title of this product is ' + product.title);
});

POST /cart/add.js

A product variation can be added to the cart using this call.

POST data is required and takes the form:

{
  id: 234234,
  quantity: 2
}

If the product uses custom options, then a composite variation id is used indicate which combination of custom options is to be used with the variation.

{
  id: '334234_1',
  quantity: 2
}

The quantity indicates how many items you wish to add to the cart for the specified variation.

The data can also be sent from a form if it is serialized.

  jQuery.post('/cart/add.js', $('form[action="/cart/add"]').serialize());

You can also add an item to the cart with Line Item Properties, in addition to the quantity and id.

jQuery.post('/cart/add.js', {
  id: 3453663,
  quantity: 1,
  properties: {
    'gift wrapping': 'Yes',
    'card message': 'So pleased to meet you last week.'
  }
});

Only a single variation can be added to the cart with this Ajax request. Multiple variations can be added by queuing up several Ajax requests synchronously.

If the variation is added to the cart successfully, the cart line item is returned in JSON format.

{
  "cart_index": 1,
  "variant_id": 1771,
  "product_id": 1504,
  "options_id": 1,
  "title": "Artichoke - Tiny - Silk metallic<span><br/>Signs<br/>Sign 10% Off</span>",
  "price": "6.77",
  "discount": "1.35",
  "quantity": 2,
  "line_price": "12.19",
  "sku": "9111003",
  "grams": 20,
  "note": null,
  "taxable": true,
  "message": "",
  "vendor": "Spiffy Stores",
  "url": "/products/artichoke",
  "image": "/site/products/1504_artichoke_01_full.jpg",
  "handle": "artichoke",
  "product_title": "Artichoke",
  "product_description": "The Globe Artichoke is a perennial thistle originating in southern Europe around the Mediterranean. It grows to 1.5-2 m tall, with arching, deeply ...",
  "product_type": "Vegetables",
  "variant_title": "Tiny",
  "variant_options": [
    "Tiny"
  ],
  "requires_shipping": true
}

If the item is already in the cart, then the quantity will be equal to the new quantity for that item.

If a non-existent variation is added to the cart, an error will be returned instead, as follows:

{
  "message": "Cart Error",
  "status": 422,
  "description": "Variation not found"
}

All error messages are returned as JSON data structures.

The error code is:

422 (Unprocessable Entity)

Other errors may be returned if exception conditions with the cart are detected. For example, each cart supports only a limited number of items and if this value is exceeded, then an error is returned.

If an item is sold out, then the error message returned is:

"The product 'VARIATION' is already sold out"

If there are items in stock, then it is possible add these items to the cart. The actual number of items requested are reserved, but the actual inventory check is not performed until the customer proceeds to the checkout where the actual number of items ordered may need to be reduced if there are not enough still in stock to meet the requested number.

GET /cart.js

Retrieve the cart contents as a JSON data structure.

For example, the cart will look something like this:

{
  "token": "618409804635da614f1060f363bec493",
  "note": "This is a test cart note.",
  "attributes": "",
  "total_price": "24.37",
  "cart_discount": "2.71",
  "total_weight": 0,
  "item_count": 4,
  "items": [
    {
      "cart_index": 1,
      "variant_id": 1771,
      "product_id": 1504,
      "options_id": 1,
      "title": "Artichoke - Tiny - Silk metallic<span><br/>Signs<br/>Sign 10% Off</span>",
      "price": "6.77",
      "discount": "2.71",
      "quantity": 4,
      "line_price": "24.37",
      "sku": "9111003",
      "grams": 40,
      "note": null,
      "taxable": true,
      "message": "",
      "vendor": "Spiffy Stores",
      "url": "/products/artichoke",
      "image": "/site/products/1504_artichoke_01_full.jpg",
      "handle": "artichoke",
      "product_title": "Artichoke",
      "product_description": "The Globe Artichoke is a perennial thistle originating in southern Europe around the Mediterranean. It grows to 1.5-2 m tall, with arching, deeply ...",
      "product_type": "Vegetables",
      "variant_title": "Tiny",
      "variant_options": [
        "Tiny"
      ],
      "requires_shipping": true
    }
  ],
  "exchange_rate": 0.6297373387,
  "currency": "GBP"
}

Example of a response for an empty cart:

{
  "token": "618409804635da614f1060f363bec493",
  "note": "",
  "attributes": "",
  "total_price": "0.00",
  "cart_discount": "0.00",
  "total_weight": 0,
  "item_count": 0,
  "items": [
    
  ],
  "exchange_rate": 0.6297373387,
  "currency": "GBP"
}

POST /cart/update.js

This call can be used to change cart attributes, the cart note and the line item quantities in the cart.

POST data is required and takes the following forms.

For a single line item, just provide the variation id and quantity required.

{
  id: 72331312,
  quantity: 2
}

If the product uses custom options, then a composite variation id is used indicate which combination of custom options is to be used with the variation.

{
  id: '334234_1',
  quantity: 2
}

Multiple line items can be updated in a single call, where the keys of the updates are the variation ids of the required line items.

{
  updates: { 12345: 2, 67890: 3 }
}

The quantity indicates how many items you wish to add to the cart for the specified variation.

The data may also be sent in serialized form from the form data fields.

The contents of the cart in JSON format are returned from this call.

The cart note can also be updated.

{
  note: "This is an updated cart note."
}

Similarly, the cart attributes can be updated.

{
  attributes[key1]: "First attribute",
  attributes[key2]: "Second attribute"
} 

The result of this call would be:

{
  "token": "618409804635da614f1060f363bec493",
  "note": "",
  "attributes": {
    "key1": "First attribute",
    "key2": "Second attribute"
  },
  "total_price": "0.00",
  "cart_discount": "0.00",
  "total_weight": 0.0,
  "item_count": 0,
  "items": [],
  "exchange_rate": 0.6297373387,
  "currency": "AUD"
}

If the cart is empty the following jQuery example will add 2 items of variation 2345345 and 3 items of variant 364566:

jQuery.post('/cart/update.js', { updates: { 2345345: 2, 364566: 3 } });

This same result can be achieved with slightly different syntax:

jQuery.post('/cart/update.js', "updates[2345345]=2&updates[364566]=3");

Similarly, a single line item can be updated as follows:

jQuery.post('/cart/update.js', { updates: { 2345345: 2 } });

Finally, line items can be removed from the cart by setting their quantity to zero:

jQuery.post('/cart/update.js', { updates: { 2345345: 0, 364566: 0 } });

The properties of a line item can be set when an item is added to the cart. This means that the same variation can exist more than once in a cart, as each line item can have different customization data.

This means that it may not be possible to identify a unique variation in a cart by its id, as multiple line items in the cart may have the same id.

If this is the case, then the only way to update the line item quantities is to provide an array of new quantities for each line item, where the order of elements in the array matches the order of line items in the cart.

When you use this method of updating line items, the number of elements in the array must match the number of line items in the cart.

For example, if you have 3 line items in the cart, with quantities 1, 2 and 3, and you want to update these quantities to 3, 2 and 1, you can use the following example:

jQuery.post('/cart/update.js', { updates: [3, 2, 1] });

The above method requires you to update the quantities of all line items in the cart. It's possible to change just one line item by using the /cart/change.js call instead, where the line item is specified using a 1-origin based line item index.

jQuery.post('/cart/change.js', { line: 1, quantity: 1 });

Similarly, to change the quantity of the second line item in the cart, we use this example:

jQuery.post('/cart/change.js', { line: 2, quantity: 1 });

POST /cart/change.js

This call updates the quantity of an item already in the cart.

POST data is required and takes the form:

{
  id: 234234,
  quantity: 2
}

If the product uses custom options, then a composite variation id is used indicate which combination of custom options is to be used with the variation.

{
  id: '334234_1',
  quantity: 2
}

The quantity indicates how many items you wish to add to the cart for the specified variation.

The cart is returned in response to this call in JSON format.

As described in the previous section, line item properties mean that line items cannot necessarily be uniquely identified in the cart by their id. In these cases it is necessary to use the 1-origin based index of the line item in the cart.

{
  line: 1,
  quantity: 10
}

For example,

jQuery.post('/cart/change.js', { line: 1, quantity: 10 });

The '/cart/update.js' and '/cart/change.js' calls appear to do very similar things, but there are important differences.

The '/cart/update.js' call allows several line items to be updated at once, including items that may not yet be in the cart. These new items will be automatically added to the cart. In addition, the cart note and attributes can also be updated using this call.

The '/cart/change.js' call can only update the quantity of one line item at a time, and that line item must alreay be in the cart.

If the item is not in the cart, '/cart/change.js' will not add it.

POST /cart/clear.js

This call empties the cart by setting the quantities of all line items in the cart to zero.

An empty cart is returned in JSON format. The cart attributes and note are preserved.

{
  "token": "618409804635da614f1060f363bec493",
  "note": "",
  "attributes": "",
  "total_price": "0.00",
  "cart_discount": "0.00",
  "total_weight": 0,
  "item_count": 0,
  "items": [
    
  ],
  "exchange_rate": 0.6297373387,
  "currency": "GBP"
}

Processing Requests Synchronously

Ajax requests that update the cart must be queued and sent synchronously to the server.

A request queue can be created simply by using a Javascript array.

Spiffy.queue = [];

All you need to do is to search through all the quantity fields, and add the requests to the queue.

jQuery('.quantity').each(function() {
  Spiffy.queue.push( {
    variantId: jQuery(this).data('variant-id'),
    quantity: parseInt(jQuery(this).val(), 10) || 0
  });
});

Once the queue is ready to process, you can call the Ajax API, using the wrapper function Spiffy.addItem for example.

The callback for this Ajax request should be a function that removes the most recently processed request from Spiffy.queue and then calls Spiffy.addItem again to process the next request, for as long as requests remain in the queue to be processed.

For example:

Spiffy.procesQueue = function() {
  if (Spiffy.queue.length > 0) {
    var request = Spiffy.queue.shift();
    Spiffy.addItem(request.variantId, request.quantity, Spiffy.processQueue);
  } else {
    // If the queue is empty, then redirect back to the cart page.
    document.location.href = '/cart';
  }
};