Add cart items

Add an item to a new or existing cart. If a valid session ID is passed, the item will be added to the cart owned by the session user. If a user can't be found or if the session ID is invalid or if the JWT is not able to retrieve an existing cart, a new cart and user will be created before adding the item.

Request Parameters

🏷️ header · unmarked parameters are query params

ParameterTypeRequiredDescription
Locally-Api-Token 🏷️stringYesLocally API token must be passed in the header to authenticate the API consumer.
Locally-Api-Session-Id 🏷️stringYesSession ID must be passed in the header to persist the user session. Can expire.
Locally-Pl-Jwt 🏷️stringNoJSON Web Token passed in the header to identify the user. Does not expire.
host_domainstringNoThe domain from which the request is being made.
store_idintegerYesThe ID of the store.
upcstringYesThe UPC code of the item.

Example Request

curl --get 'https://www.locally.com/headless/api/1.0/cart/items/add' \
--header 'Locally-Api-Token: {{API_TOKEN}}' \
--header 'Locally-Api-Session-Id: {{SESSION_ID}}' \
--data-urlencode 'store_id={{STORE_ID}}' \
--data-urlencode 'upc={{UPC}}' \
--data-urlencode 'host_domain=www.example.com'
const params = new URLSearchParams({
  store_id: '{{STORE_ID}}',
  upc: '{{UPC}}',
  host_domain: 'www.example.com'
});

const response = await fetch(`https://www.locally.com/headless/api/1.0/cart/items/add?${params}`, {
  headers: {
    'Locally-Api-Token': '{{API_TOKEN}}',
    'Locally-Api-Session-Id': '{{SESSION_ID}}'
  }
});

const data = await response.json();
import requests

response = requests.get(
    "https://www.locally.com/headless/api/1.0/cart/items/add",
    params={
        "store_id": "{{STORE_ID}}",
        "upc": "{{UPC}}",
        "host_domain": "www.example.com",
    },
    headers={
        "Locally-Api-Token": "{{API_TOKEN}}",
        "Locally-Api-Session-Id": "{{SESSION_ID}}",
    },
)

data = response.json()

On a first request you can omit the Locally-Api-Session-Id header — a new user, cart, and session are created automatically, and the response returns data.session.id and data.cart_hash_jwt to pass on subsequent calls. To flag the order for ROPIS (hold for pickup) instead of BOPIS, add hold=true as described in Create a Checkout Experience.

Example Response

{
    "success": true,
    "data": {
        "n_in_cart": 1,
        "cart_hash": "QE3QL6",
        "cart_content": {
            "user": {
                "id": 999,
                "email": "[email protected]",
                "first_name": "",
                "last_name": "",
                "phone": "",
                "preferred_zip": "60605",
                "preferred_country": "US"
            },
            "cart": {
                "id": 999,
                "user_id": 999,
                "hash": "QE3QL6",
                "subtotal": 100,
                "tax_total": 10.10,
                "shipping_cost_total": 0,
                "grand_total": 110.10,
                "first_name": "",
                "last_name": "",
                "address": "",
                "address_2": "",
                "city": "",
                "state": "",
                "zip": "",
                "email": "",
                "phone": "",
                "country": "",
                "locale": "en-us",
                "origin": "www.example.com",
                "for_hold": 0,
                "for_delivery": 0,
                "delivery_first_name": "",
                "delivery_last_name": "",
                "delivery_address": "",
                "delivery_address_2": "",
                "delivery_city": "",
                "delivery_state": "",
                "delivery_zip": "",
                "delivery_country": "",
                "delivery_fee_total": 0,
                "is_test": 0,
                "delivery_choice": "",
                "store_delivery_fee": 0,
                "delivery_notes": "",
                "coupon_discount_total": 0,
                "coupon_code": "",
                "coupon_discount_reason": "",
                "for_ship_to_store": 0,
                "cart_currency": "USD",
                "items": [
                    {
                        "id": 999,
                        "qty": 1,
                        "upc": "000000000000",
                        "product_name": "ACME Outfitters Widget",
                        "product_company_name": "ACME Outfitters",
                        "product_image": "image.jpg",
                        "product_color": "Red",
                        "product_size": "M",
                        "product_price": 100,
                        "product_id": 999999,
                        "store_id": 99999,
                        "subtotal": 100,
                        "tax_total": 10.10,
                        "shipping_cost": 0,
                        "grand_total": 110.10,
                        "qty_available": 10,
                        "message": "",
                        "fulfillment_type": 0,
                        "product_currency": "USD",
                        "product_company_id": 999,
                        "coupon_discount_total": 0,
                        "vat": 0,
                        "tax_rate": 10.25,
                        "product": {
                            "id": 999999,
                            "name": "ACME Outfitters Widget",
                            "company_id": 999,
                            "style_number": "99999",
                            "image": "image.jpg",
                            "long_description": "Lorem ipsum.",
                            "average_rating": 5,
                            "n_reviews": 1,
                            "upc_data": null,
                            "company": null
                        }
                    }
                ],
                "custom_cart_text": ""
            },
            "country": {
                "id": 99,
                "name": "United States",
                "code": "US",
                "primary_currency": "USD",
                "secondary_currency": "",
                "primary_locale": "en-us",
                "phone_prefix": "1",
                "display_marketing_consent": "",
                "consent_checkbox_default_state": 0,
                "code_3": "USA",
                "display_brand_marketing_consent": ""
            },
            "cart_error": 0,
            "cart_disclaimer": "By continuing you agree to our <a href=https:\/\/www.locally.com\/terms target=_blank>terms of service<\/a>",
            "cart_store": {
                "id": 99999,
                "name": "ACME Outfitters Chicago",
                "address": "123 ACME St.",
                "zip": "00000",
                "company_id": 999,
                "lat": "41.91136867",
                "lng": "-87.67771437",
                "phone": "(312) 555-0142",
                "mon_time_open": 1100,
                "mon_time_close": 1900,
                "tue_time_open": 1100,
                "tue_time_close": 1900,
                "wed_time_open": 1100,
                "wed_time_close": 1900,
                "thu_time_open": 1100,
                "thu_time_close": 1900,
                "fri_time_open": 1100,
                "fri_time_close": 1900,
                "sat_time_open": 1100,
                "sat_time_close": 1900,
                "sun_time_open": 1100,
                "sun_time_close": 1700,
                "address_2": "",
                "city": "Chicago",
                "state": "IL",
                "country": "US",
                "timezone": "America\/Chicago",
                "average_rating": 5,
                "n_reviews": 3,
                "image": "image.jpg",
                "web_address": "https:\/\/www.example.com",
                "is_temporarily_closed": 0,
                "area": null,
                "store_hours": [
                    {
                        "id": 1,
                        "store_id": 99999,
                        "type": 0,
                        "custom_label": null,
                        "dow": 0,
                        "single_day": null,
                        "closed": 0,
                        "start_time": 700,
                        "end_time": 2000,
                        "group": 1,
                        "is_closed": 0
                    },
                    {
                        "id": 2,
                        "store_id": 99999,
                        "type": 0,
                        "custom_label": null,
                        "dow": 1,
                        "single_day": null,
                        "closed": 0,
                        "start_time": 700,
                        "end_time": 2000,
                        "group": 1,
                        "is_closed": 0
                    }
                ],
                "pickup_time_slots": {
                    "time": null,
                    "days": null
                },
                "store_vat_details": {
                    "id": 99999,
                    "uses_vat": 0,
                    "sales_tax_label": ""
                },
                "acquisition_options": {
                    "bopis": 1,
                    "sdd": 1,
                    "ropis": 1
                }
            }
        },
        "delivery_options": null,
        "cart_hash_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYXJ0X2hhc2giOiJRRTNRTDYiLCJjcmVhdGVkX2F0IjoxNzIxNDA4MDAwfQ.sQ5xL0y3fY8pWq2ZbNvA7cRkT1uHdGmE4jXoPiC6VnM",
        "session": {
            "id": "vD2kq9mXw4bT7nR5cJ1sL8fA3gH6pZ0yE2uN4iK9"
        }
    },
    "msg": ""
}
{
    "success": false,
    "data": {
        "cart_hash": "QE3QL6",
        "cart_content": {
            "cart_error": "Sorry, this purchase option is no longer available at this store."
        },
        "cart_hash_jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYXJ0X2hhc2giOiJRRTNRTDYiLCJjcmVhdGVkX2F0IjoxNzIxNDA4MDAwfQ.sQ5xL0y3fY8pWq2ZbNvA7cRkT1uHdGmE4jXoPiC6VnM",
        "session": {
            "id": "vD2kq9mXw4bT7nR5cJ1sL8fA3gH6pZ0yE2uN4iK9"
        }
    },
    "msg": ""
}

Response Explanation

  • successtrue for a healthy cart. Cart-level failures still return HTTP 200 with success: false and the reason in data.cart_content.cart_error; other failures use HTTP 4xx/5xx with msg and error_code.
  • data.n_in_cart — Count of distinct line items in the cart, not the summed quantity — a single item with qty: 2 still returns n_in_cart: 1.
  • data.cart_hash — The cart's permanent short identifier, identical to data.cart_content.cart.hash. Use it as the hash parameter when placing the order.
  • data.cart_content.cart.for_hold — Path-to-purchase flags: for_hold: 1 marks a ROPIS hold order (item added with hold=true); for_delivery: 1 same-day delivery; for_ship_to_store: 1 ship-to-store.
  • data.cart_content.cart.subtotal — All money fields (subtotal, tax_total, grand_total, items[].product_price) are decimal amounts in cart_currency — dollars and cents, never integer cents. items[].tax_rate is a percentage (10.25 means 10.25%).
  • data.cart_content.cart.items[].id — Cart item line ID — the {{ITEM_ID}} key for Update cart's qty array and its remove_item parameter. Removal only works before the item is ordered (Cart Item Statuses).
  • data.cart_content.cart_error0 when the cart is healthy. On a cart-level failure it becomes a human-readable message (for example, a purchase option no longer available) and success flips to false.
  • data.cart_content.cart_store.acquisition_options — Purchase options the cart's store supports for these items, as 1 flags: bopis, ropis, sdd; sts appears instead for ship-to-store carts.
  • data.cart_hash_jwt — Non-expiring signed JWT encoding the cart hash. Save it and send it as the Locally-Pl-Jwt header to retrieve or update this cart after the session ID expires.
  • data.session.id — The current session ID. It can change between calls, so always send the latest value in the Locally-Api-Session-Id header on your next request. Session IDs eventually expire.
Query Params
string

The domain from which the request is being made.

int32
required

The ID of the store.

string
required

The UPC code of the item.

Headers
string
required

Locally API token must be passed in the header to authenticate the API consumer

string
required

Session ID must be passed in the header to persist the user session. Can expire.

string

JSON Web Token passed in the header to identify the user. Does not expire.

Responses
200

Successful

400

Bad Request

401

Unauthorized

402

Request Failed

403

Forbidden

404

Not Found

429

Too Many Requests

500

Server Error

Language
LoadingLoading…
Response
Click Try It! to start a request and see the response here!