Cart API reference

The Cart API is used to interact with a cart during a customer's session. This guide shows how to use the Cart API to update cart line items, add cart attributes and notes, and generate shipping rates.

POST /cart/add.js

Use the POST /cart/add.js endpoint to add one or multiple variants to the cart.

In the following example, quantity is the amount of the variant that you want to add and id is the variant ID of that variant. You can add multiple variants to the cart by appending more objects in the items array.

items: [
  {
   id: 36110175633573,
   quantity: 2
  }
]

To send a serialized Add to Cart form, specify the following post data:

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

You can also add to the cart with line item properties, not just a quantity and ID:

jQuery.post('/cart/add.js', {
  items: [
    {
      quantity: 1,
      id: 794864229,
      properties: {
        'First name': 'Caroline'
      }
    }
  ]
});

Add line item properties

You can add a variant to the cart with line item properties with an accompanying properties object.

items: [
  {
    quantity: 1,
    id: 794864229,
    properties: {
      'First name': 'Caroline'
    }
  }
]

View response

{
  "items": [
    {
      "id": 794864229,
      "quantity: 1,
      // ...
      "properties" : {
        'First name': 'Caroline'
      }
    }
  ]
}

Add a selling plan

You can add a variant with a selling plan to the cart with an accompanying selling_plan parameter.

items: [
  {
    quantity: 1,
    id: 794864229,
    selling_plan: 183638
  }
]

View response

The response object has a selling_plan_allocation property.

{
  "items": [
    {
      "id": 794864229,
      // ...
      "selling_plan_allocation": {
        "price": 3120,
        "compare_at_price": 3900,
        "per_delivery_price": 3120,
        "selling_plan": {
          "id": 183638,
          "name": "Pay every month, delivery every month | save 20%",
          "description": "No commitment · Auto-renews · Skip or cancel anytime",
          "options": [{
            "name": "Delivery Frequency",
            "position": 1,
            "value": "Month"
          }, {
            "name": "Billing Frequency",
            "position": 2,
            "value": "Month"
          }],
          "recurring_deliveries": true
        }
      }
    }
  ]
}

Example API calls

Below is a simplified POST using the fetch API. The formData object is built in JavaScript, so the Content-Type should be set to application/json in the headers object.

let formData = {
 'items': [{
  'id': 36110175633573,
  'quantity': 2
  }]
};

fetch('/cart/add.js', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(formData)
})
.then(response => {
  return response.json();
})
.catch((error) => {
  console.error('Error:', error);
});

View response

The following response shows the JSON of the line items associated with the added variants. If an item is already in the cart, then quantity is equal to the new quantity for that item.

{
  "items": [
    {
      "id": 36110175633573,
      "title": "Red Rain Coat - Small",
      "key": "794864229:03af7a8cb59a4c3c45595c76fa8cb53c",
      "price": 12900,
      "line_price": 12900,
      "quantity": 2,
      "sku": null,
      "grams": 0,
      "vendor": "Shopify",
      "properties": {},
      "variant_id": 794864229,
      "gift_card": false,
      "url": "/products/red-rain-coat?variant=794864229",
      "featured_image": {
        "url": "http://cdn.shopify.com/s/files/1/0040/7092/products/red-rain-coat.jpeg?v=1402604893",
        "aspect_ratio": 1.0,
        "alt": "Red rain coat with a hood"
      },
      "image": "http://cdn.shopify.com/s/files/1/0040/7092/products/red-rain-coat.jpeg?v=1402604893",
      "handle": "red-rain-coat",
      "requires_shipping": true,
      "product_title": "Red Rain Coat",
      "product_description": "A bright red rain coat for rainy days!",
      "product_type": "Coat",
      "properties" : null,
      "variant_title": "Red",
      "variant_options": ["Red"],
      "options_with_values": [
        {
          "name": "Color",
          "value": "Red"
        }
      ]
    }
  ]
}

Alternatively, you can use the FormData constructor and target the desired add-to-cart form:

let addToCartForm = document.querySelector('form[action="/cart/add"]');
let formData = new FormData(addToCartForm);

fetch('/cart/add.js', {
  method: 'POST',
  body: formData
})
.then(response => {
  return response.json();
})
.catch((error) => {
  console.error('Error:', error);
});

Response

The response for successful POSTs is a JSON object of the line items associated with the added items.

If an added item was already in the cart, then the quantity is equal to the new quantity for that cart line item. Keep in mind, however, that added items are split on to separate line items when their prices differ. Changes in price are typically the result of automatic discounts or Shopify Scripts.

items: [
  {
    id: 36323170943141,
    quantity: 1
  },
  {
    id: 36323170943141,
    selling_plan: 6717605,
    quantity: 1
  }
]

View response

{
  "items":[
    {
      "id":36323170943141,
      "properties":null,
      "quantity":1,
      "variant_id":36323170943141,
      "key":"36323170943141:b15f59bb6d406f2f45dc383a5493bdb8",
      "title":"Great Granola Bar",
      "price":2000,
      "original_price":2000,
      "discounted_price":2000,
      "line_price":2000,
      "original_line_price":2000,
      "total_discount":0,
      "discounts":[],
      "sku":"",
      "grams":0,
      "vendor":"shopify",
      "taxable":true,
      "product_id":5680114172069,
      "product_has_only_default_variant":true,
      "gift_card":false,
      "final_price":2000,
      "final_line_price":2000,
      "url":"/products/great-granola-bar?variant=36323170943141",
      "featured_image":{
        "aspect_ratio":1.504,
        "alt":"Great Granola Bar",
        "height":1277,
        "url":"https://cdn.shopify.com/s/files/1/0401/3218/2181/products/fallon-michael-h2UH2674Bg4-unsplash.jpg?v=1600796940",
        "width":1920
      },
      "image":"https://cdn.shopify.com/s/files/1/0401/3218/2181/products/fallon-michael-h2UH2674Bg4-unsplash.jpg?v=1600796940",
      "handle":"great-granola-bar",
      "requires_shipping":true,
      "product_type":"",
      "product_title":"Great Granola Bar",
      "product_description":"The great granola bar, everyone has been talking about it. Subscribe when you can!",
      "variant_title":null,
      "variant_options":[
        "Default Title"
      ],
      "options_with_values":[
        {
          "name":"Title",
          "value":"Default Title"
        }
      ],
      "line_level_discount_allocations":[ ],
      "line_level_total_discount":0
    },
    {
      "id":36323170943141,
      "properties":null,
      "quantity":1,
      "variant_id":36323170943141,
      "key":"36323170943141:322e2af74da821ca095964e07b7270b5",
      "title":"Great Granola Bar",
      "price":1700,
      "original_price":1700,
      "discounted_price":1700,
      "line_price":1700,
      "original_line_price":1700,
      "total_discount":0,
      "discounts": ],
      "sku":"",
      "grams":0,
      "vendor":"shopify",
      "taxable":true,
      "product_id":5680114172069,
      "product_has_only_default_variant":true,
      "gift_card":false,
      "final_price":1700,
      "final_line_price":1700,
      "url":"/products/great-granola-bar?selling_plan=6717605/u0026variant=36323170943141",
      "featured_image":{
        "aspect_ratio":1.504,
        "alt":"Great Granola Bar",
        "height":1277,
        "url":"https://cdn.shopify.com/s/files/1/0401/3218/2181/products/fallon-michael-h2UH2674Bg4-unsplash.jpg?v=1600796940",
        "width":1920
      },
      "image":"https://cdn.shopify.com/s/files/1/0401/3218/2181/products/fallon-michael-h2UH2674Bg4-unsplash.jpg?v=1600796940",
      "handle":"great-granola-bar",
      "requires_shipping":true,
      "product_type":"",
      "product_title":"Great Granola Bar",
      "product_description":"The great granola bar, everyone has been talking about it. Subscribe when you can!",
      "variant_title":null,
      "variant_options":[
        "Default Title"
      ],
      "options_with_values":[
        {
          "name":"Title",
          "value":"Default Title"
        }
      ],
      "line_level_discount_allocations":[ ],
      "line_level_total_discount":0,
      "selling_plan_allocation":{
        "price_adjustments":[
          {
            "position":1,
            "price":1700
          }
        ],
        "price":1700,
        "compare_at_price":2000,
        "per_delivery_price":1700,
        "selling_plan":{
          "id":6717605,
          "name":"Delivered every week",
          "description":null,
          "options":[
            {
              "name":"Delivery every",
              "position":1,
              "value":"1 Week(s)"
            }
          ],
          "recurring_deliveries":true,
          "price_adjustments":[
            {
              "order_count":null,
              "position":1,
              "value_type":"percentage",
              "value":15
            }
          ]
        }
      }
    }
  ]
}

Error responses

If the exact quantity specified for one of the items can't be added to the cart (for example, you are trying to add 9 items, 2 are already in the cart, and 10 are in stock), then no items are added the cart. The JSON formatted error returned is:

{
  "status": 422,
  "message": "Cart Error",
  "description": "You can't add more Messenger Bag to the cart."
}

The error code is:

422 (Unprocessable Entity)

If the product is entirely sold out, then the following error is returned:

The product '#{item.name}' is already sold out.

If the product is not sold out, but all of its stock is in the cart, then the following error is returned:

All #{item.inventory_quantity} #{item.name} are in your cart.

GET /cart.js

Use the GET /cart.js endpoint to get the cart as JSON.

All monetary properties are returned in the customer's presentment currency. To check the customer's presentment currency, you can use the currency field in the response. To learn more about selling in multiple currencies, refer to Migrate your app to support multi-currency.

Responses

JSON of a cart

View response

{
  "token": "1d19a32178501c44ef2223d73c54d16d",
  "note": "Hello!",
  "attributes": {
    "Gift wrap": "Yes"
  },
  "total_price": 9100,
  "total_weight": 0,
  "item_count": 3,
  "items": [
    {
      "id": 794864229,
      "properties": {},
      "quantity": 1,
      "variant_id": 794864229,
      "key": "794864229:03af7a8cb59a4c3c45595c76fa8cb53c",
      "title": "Red Rain Coat - Small",
      "price": 12900,
      "line_price": 12900,
      "final_price": 12900,
      "final_line_price": 12900,
      "sku": null,
      "grams": 0,
      "vendor": "Shopify",
      "taxable": true,
      "product_id": 388319916,
      "product_has_only_default_variant": false,
      "gift_card": false,
      "url": "/products/red-rain-coat?variant=794864229",
      "featured_image": {
        "url": "http://cdn.shopify.com/s/files/1/0040/7092/products/red-rain-coat.jpeg?v=1402604893",
        "aspect_ratio": 1.0,
        "alt": "Red rain coat with a hood"
      },
      "image": "http://cdn.shopify.com/s/files/1/0040/7092/products/red-rain-coat.jpeg?v=1402604893",
      "handle": "red-rain-coat",
      "requires_shipping": true,
      "product_title": "Red Rain Coat",
      "product_description": "A bright red rain coat for rainy days!",
      "product_type": "Coat",
      "variant_title": "Red",
      "variant_options": ["Red"],
      "options_with_values": [
        {
          "name": "Color",
          "value": "Red"
        }
      ]
    },
    {
      "id": 794864101,
      "properties": {},
      "quantity": 2,
      "variant_id": 794864101,
      "key": "794864101:816a55d9a53cd82281f8fdcfe967db14",
      "title": "Gray Fedora",
      "price": 2650,
      "line_price": 0,
      "final_price": 2650,
      "final_line_price": 5300,
      "sku": null,
      "grams": 0,
      "vendor": "Shopify",
      "taxable": true,
      "product_id": 388319892,
      "product_has_only_default_variant": false,
      "gift_card": false,
      "url": "/products/gray-fedora?variant=794864101",
      "featured_image": {
        "url": "http://cdn.shopify.com/s/files/1/0040/7092/products/gray-fedora.jpeg?v=1402604885",
        "aspect_ratio": 1.0,
        "alt": "Gray fedora made of straw"
      },
      "image": "http://cdn.shopify.com/s/files/1/0040/7092/products/gray-fedora.jpeg?v=1402604885",
      "handle": "gray-fedora",
      "requires_shipping": true,
      "product_title": "Gray Fedora",
      "product_description": "A gray hat for looking cool!",
      "product_type": "Hats",
      "variant_title": "Gray",
      "variant_options": ["Gray"],
      "options_with_values": [
        {
          "name": "Color",
          "value": "Gray"
        }
      ],
      "line_level_discount_allocations": [
        {
          "amount": 500,
          "discount_application": {
            "type": "script",
            "key": "a8a3d7aa-7d00-4827-a2e1-b03c32160bf2",
            "title": "5 Dollar Off",
            "description": null,
            "value": "5.00",
            "created_at": "2019-04-10T20:49:10.023Z",
            "value_type": "fixed_amount",
            "allocation_method": "one",
            "target_selection": "explicit",
            "target_type": "line_item",
            "total_allocated_amount": 500
          }
        }
      ]
    }
  ],
  "requires_shipping": true,
  "currency": "CAD",
  "items_subtotal_price": 18200,
  "cart_level_discount_applications": [
    {
      "type": "automatic",
      "key": "059b5e54-3c5d-4e7e-b377-8e09d8376269",
      "title": "50% Summer Deal",
      "description": null,
      "value": "50.0",
      "created_at": "2019-04-10T20:49:00.148Z",
      "value_type": "percentage",
      "allocation_method": "across",
      "target_selection": "all",
      "target_type": "line_item",
      "total_allocated_amount": 9100
    }
  ]
}

JSON of an empty cart

View response

{
  "token": "1d19a32178501c44ef2223d73c54d16d",
  "note": null,
  "attributes": {},
  "total_price": 0,
  "total_weight": 0,
  "item_count": 0,
  "items": [],
  "requires_shipping": false,
  "currency": "CAD"
}

POST /cart/update.js

Use the POST /cart/update.js endpoint to update the cart's line item quantities, note, or attributes. You can submit a serialized cart form, or submit separate updates to a cart's line items, note, or attributes.

Update line items

Post an updates object with key-value pairs. The key is the line item's variant_id.

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

This post yields the same result:

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

The /cart/update.js endpoint adds new line items to the cart if the variant_id provided doesn't match any line item already in the cart. However, if the variant_id matches multiple line items, then the first matching line item is updated.

You can update a single line item when there are multiple line items in the cart. For example, the following post updates the quantity of only variant 794864053 to 5:

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

Finally, you can remove both variant 794864053 and variant 794864233 from the cart with the following:

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

You can also submit an array of numbers to /cart/update.js provided the size of the array matches the number of line items in the cart. Each number in the array sets the quantity for the corresponding line item in the cart.

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

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

Update cart note

Post a note character string. The following is an example of post data for a note:

{
  note: 'This is a note about my order'
}

Update cart attributes

Post an attributes object with key-value pairs. The key is the name of the attribute you want to update. The following is an example of post data for cart attributes:

{
  attributes: {
    'Gift wrap': 'Yes'
  }
}

This version yields the same result:

  jQuery.post('/cart/update.js', "attributes[Gift wrap]=Yes");
}

Response

The JSON of the cart.

Error responses

If a variant ID is provided that either doesn't exist or isn't available in the online store channel, then the endpoint returns the following error:

{
  "status": 404,
  "message": "Cart Error"
  "description": "Cannot find variant"
}

When a new variant is added to the cart and the quantity exceeds what's available, the result is a 422 error:

{
  "status": 422,
  "message": "Cart Error",
  "description": "You can only add 8 Messenger Bag to the cart."
}

POST /cart/change.js

The /cart/change.js endpoint changes the quantity and properties object of a cart line item. Only items already in your cart can be changed, and only one line item at a time can be changed.

Post data requires either an id or line property to identify the line item to be changed. The id value is the line item's variant_id or the line item's key.

{
  'id': 794864053,
  'quantity': 3
}

A cart can have multiple line items that share the same variant_id when variants have different line item properties, or automatic discounts create variants at different prices. To account for this, use the line property when updating the cart. The value of line is the 1-based index position of the item in the cart.

{
  'line': 1,
  'quantity': 3
}

Update quantities

The quantity property is the new quantity you want for the line item. The quantity value must be an integer.

The following code updates the second line item in the cart:

{
  'line': 2,
  'quantity': 1
}

You can remove a cart line item by setting the quantity to 0:

{
  'line': 2,
  'quantity': 0
}

Update properties

The properties property sets the line item properties. Its value must be an object of key-value pairs.

The following code changes the properties of the second line item in the cart:

{
  'line': 2,
  'properties': { 'gift_wrap': true }
}

Whenever a POST includes properties, it overwrites the entire properties object. Any key-value pairs that were already in the properties object are erased.

It's not possible to set a line item's properties property an empty object once a value is set. If you need to remove all line item properties, then you need to remove the entire line item.

Response

The JSON of the cart.

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

Error responses

If the item that you're attempting to change isn't already in the cart, then /cart/change.js doesn't add it. Instead, it returns a 404 error.

POST /cart/clear.js

Use the POST /cart/clear.js endpoint to set all quantities of all line items in the cart to zero.

Response

The JSON of an empty cart. This does not remove cart attributes nor the cart note.

{
  "token": "1d19a32178501c44ef2223d73c54d16d",
  "note": null,
  "attributes": {},
  "total_price": 0,
  "total_weight": 0,
  "item_count": 0,
  "items": [],
  "requires_shipping": false
}

Generate shipping rates

Use the POST /cart/prepare_shipping_rates.json and GET /cart/async_shipping_rates.json endpoints to generate shipping rates:

  • The POST /cart/prepare_shipping_rates.json endpoint initiates the process of calculating shipping rates for the cart given a destination.
  • The GET /cart/async_shipping_rates.json endpoint returns the shipping rates results if the calculations have finished.

Example prepare_shipping_rates call

/cart/prepare_shipping_rates.json?shipping_address%5Bzip%5D=K1N+5T2&shipping_address%5Bcountry%5D=Canada&shipping_address%5Bprovince%5D=Ontario

Response

null

Example async_shipping_rates call

/cart/async_shipping_rates.json?shipping_address%5Bzip%5D=K1N+5T2&shipping_address%5Bcountry%5D=Canada&shipping_address%5Bprovince%5D=Ontario

View response

If you call async_shipping_rates with the same parameters as prepare_shipping_rates, then it checks whether Shopify has finished calculating the rates. If the shipping rates aren't ready, then the response is null.

If the shipping rates are ready, the rates are returned:

{
  "shipping_rates": [
    {
      "name": "Generic Rate",
      "presentment_name": "Generic Rate",
      "code": "Generic Rate",
      "price": "6.00",
      "markup": null,
      "source": "shopify",
      "delivery_date": null,
      "delivery_range": null,
      "delivery_days": [],
      "compare_price": null,
      "phone_required": false,
      "currency": null,
      "carrier_identifier": null,
      "delivery_category": null,
      "using_merchant_account": null,
      "carrier_service_id": null,
      "description": null,
      "api_client_id": null,
      "requested_fulfillment_service_id": null,
      "shipment_options": null,
      "charge_items": null,
      "has_restrictions": null,
      "rating_classification": null,
      "accepts_instructions": false
    },
    {
      "name": "Carrier Service Mail",
      "presentment_name": "Carrier Service Mail",
      "code": "CarrierServiceMail",
      "price": "12.46",
      "markup": "0.00",
      "source": "usps",
      "delivery_date": "2020-10-09",
      "delivery_range": [
          "2020-10-06",
          "2020-10-09"
      ],
      "delivery_days": [
          0,
          3
      ],
      "compare_price": null,
      "phone_required": true,
      "currency": null,
      "carrier_identifier": null,
      "delivery_category": null,
      "using_merchant_account": null,
      "carrier_service_id": 2,
      "description": null,
      "api_client_id": null,
      "requested_fulfillment_service_id": null,
      "shipment_options": null,
      "charge_items": null,
      "has_restrictions": null,
      "rating_classification": null,
      "accepts_instructions": false
      }
   ]
}

GET /cart/shipping_rates.json

Use the GET /cart/shipping_rates.json to get estimated shipping rates.

/cart/shipping_rates.json?shipping_address%5Bzip%5D=K1N+5T2&shipping_address%5Bcountry%5D=Canada&shipping_address%5Bprovince%5D=Ontario

View response

{
  "shipping_rates": [
    {
      "name": "Ground Shipping",
      "price": "8.00",
      "delivery_date": null,
      "source": "shopify"
    },
    {
      "name": "Expedited Shipping",
      "price": "15.00",
      "delivery_date": null,
      "source": "shopify"
    },
    {
      "name": "Express Shipping",
      "price": "30.00",
      "delivery_date": null,
      "source": "shopify"
    }
  ]
}

Private properties and attributes

Private line item properties and private cart attributes are used when you need to attach information to either cart line items or the entire cart, and you don't want the properties and attributes to be visible to the online store's visitors.

Both private properties and private cart attributes are visually hidden at checkout, but are visible to merchants within the Order details of the store admin.

Private line item properties

To make a line item property private, append an underscore (_) to the key. For example, to add a variant to cart with a private _foo property using the /cart/add.js endpoint:

items: [
  {
    'quantity': 2,
    'id': 794864229,
    'properties': {
      '_foo': 'bar'
    }
  }
]

The properties property can have a mix of private and public line item properties:

items: [
  {
    quantity: 2,
    id: 794864229,
    properties: {
      '_foo': 'bar',
      'gift_wrap': true
    }
  }
]

Hide properties in a theme

Private line item properties are available in the Liquid line_item.properties object and Ajax API. To hide private properties on the storefront, you must modify the theme's codebase.

In the following example, all properties items that begin with _ in Liquid are filtered out:

Liquid

{% for property in line_item.properties %}
  {% assign first_character_in_key = property.first | slice: 0 %}
  {% unless first_character_in_key == '_' %}
    {{ property.first }}: {{ property.last }}
  {% endunless %}
{% endfor %}

Private cart attributes

To make a cart attribute private, append a double underscore (__) to an attribute name.

Private cart attributes are not available in the Liquid cart.attributes object or the Ajax API. This means there is no code modification required to hide them in theme files. Private cart attributes also do not affect the page rendering, which allows for more effective page caching.