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'
}
}
]
{
"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
}
]
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);
});
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
}
]
{
"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
{
"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
{
"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
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
{
"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.