Search for products

Search for products by company, category, department, and filters.

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.
campaign_idintegerNoCampaign ID.
company_idintegerNoCompany ID.
categorystringNoCategory.
deptstringNoDepartment.
filtersstringNoFilters.

Example Request

curl 'https://www.locally.com/headless/api/1.0/product/search' \
--request POST \
--header 'Locally-Api-Token: {{API_TOKEN}}' \
--url-query 'company_id={{COMPANY_ID}}' \
--url-query 'category=footwear' \
--url-query 'dept=running-shoes'
const params = new URLSearchParams({
  company_id: '{{COMPANY_ID}}',
  category: 'footwear',
  dept: 'running-shoes'
});

const response = await fetch(`https://www.locally.com/headless/api/1.0/product/search?${params}`, {
  method: 'POST',
  headers: {
    'Locally-Api-Token': '{{API_TOKEN}}'
  }
});
const data = await response.json();
import requests

response = requests.post(
    "https://www.locally.com/headless/api/1.0/product/search",
    headers={"Locally-Api-Token": "{{API_TOKEN}}"},
    params={
        "company_id": "{{COMPANY_ID}}",
        "category": "footwear",
        "dept": "running-shoes",
    },
)
data = response.json()

All parameters are sent in the query string — the POST body is unused. category and dept take the category and department slugs returned in the top_level_categories and level_2_categories facets of a previous search response.

Example Response

{
  "success": true,
  "data": {
    "search_results": {
      "products": [
        {
          "style_number": "TR2-M",
          "company_id": 999,
          "id": 1234567,
          "name": "Trail Runner 2",
          "image": "image.jpg",
          "company_name": "ACME Outfitters",
          "price": 129.99,
          "min_price": 129.99,
          "max_price": 149.99,
          "price_range": 5,
          "unit_msrp": 129.99,
          "currency": "USD",
          "stock_status": 1,
          "url": "/product/1234567/acme-outfitters-trail-runner-2"
        },
        {
          "style_number": "RR1-W",
          "company_id": 999,
          "id": 1234568,
          "name": "Road Racer 1",
          "image": "image.jpg",
          "company_name": "ACME Outfitters",
          "price": 89.99,
          "min_price": 89.99,
          "max_price": 89.99,
          "price_range": 4,
          "unit_msrp": 89.99,
          "currency": "USD",
          "stock_status": 1,
          "url": "/product/1234568/acme-outfitters-road-racer-1"
        }
      ],
      "top_level_categories": [
        {
          "id": 87,
          "name": "Footwear",
          "slug": "footwear",
          "link": "/search/acme-outfitters/footwear"
        }
      ],
      "level_2_categories": [
        {
          "id": 214,
          "name": "Running Shoes",
          "slug": "running-shoes",
          "link": "/search/acme-outfitters/footwear/running-shoes"
        }
      ],
      "level_3_categories": [],
      "level_4_categories": [],
      "vendors": [
        {
          "id": 999,
          "name": "ACME Outfitters",
          "city": "Chicago",
          "state": "IL",
          "slug": "acme-outfitters",
          "url": "/search/acme-outfitters"
        }
      ],
      "base_url": "/search/acme-outfitters/footwear/running-shoes"
    },
    "page_title": "ACME Outfitters Footwear Running Shoes",
    "total_hits": 42,
    "sort_link_prepend": "/headless/api/1.0/product/search?company_id=999&category=footwear&dept=running-shoes&sort=",
    "n_visible_filters": 3,
    "n_results_per_page": 30,
    "n_pages": 2,
    "local_url": "/search/acme-outfitters/footwear/running-shoes/all-local-stores",
    "meta_description": "Products, brands and stores matching \"ACME Outfitters Footwear Running Shoes\"",
    "session": {
      "id": "abc999"
    }
  },
  "msg": ""
}

Response Explanation

  • successtrue with an empty msg on success; on failure success is false and a msg plus numeric error_code are returned (e.g. 1102 when the token can't access the requested company_id).
  • data.search_results.products[] — One row per matching product. In-stock matches are scoped to the session's location (roughly a 50-mile radius by default), and rows without a resolvable price are omitted.
  • data.search_results.products[].price — All price fields are decimal amounts in currency, not cents. min_price/max_price span the prices found across local stores (falling back to MSRP); unit_msrp is the manufacturer's suggested price.
  • data.search_results.products[].price_range — Bucket index of price along the breakpoints 0, 25, 50, 75, 100, 150, 200, 300, 500, 750, 1000 — 5 means 100–150. Powers the price facet.
  • data.search_results.products[].stock_status1 when at least one local store has the product in stock; 0 when the product is indexed for search without any local stock.
  • data.search_results.products[].url — Site-relative path built from Locally's product id and a name slug; prefix it with https://www.locally.com. Category link values, base_url, and local_url are relative in the same way.
  • data.search_results.top_level_categories[].slug — Facet slugs feed follow-up searches: pass a top-level slug as category and a level_2_categories[].slug as dept to drill down.
  • data.total_hits — Total number of matching products across all pages, not the count in this response.
  • data.n_pagestotal_hits divided by n_results_per_page (30 by default), rounded up. Fetch further pages with the zero-based page query parameter.
  • data.session.id — Locally session identifier, returned on every Headless API response. Echo it back in the Locally-Api-Session-Id header so the shopper's location and cart persist across calls.
Query Params
Headers
Responses
200

Successful

400

Bad Request

401

Unauthorized

402

Request Failed

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