Skip to content
Elara One docs

Catalogue

Products, variants, options, collections, images and prices, and how to filter, sort, include and page through the product list.

The catalogue endpoints give your storefront everything it needs to render listing and product pages. They are read-only, and only published products are ever returned.

Endpoints

EndpointReturns
GET /v1/productsA page of products, with filters, sorts and includes
GET /v1/products/price-boundsThe lowest and highest price for the current filters, for a price slider
GET /v1/products/{slug}One product, with everything included
GET /v1/collectionsA page of collections
GET /v1/collections/{slug}One collection
GET /v1/collections/{slug}/productsA page of the collection's products, with the same filters, sorts and includes as GET /v1/products
GET /v1/promotionsThe store's live public offers, for an offers strip or banner
GET /v1/countriesThe countries the store sells and ships to, for address forms

Catalogue responses are cached by the engine and cleared when the merchant changes the catalogue, so you can call them on every page view.

The building blocks

  • Products have a name, description, slug and status. Link product pages by slug.
  • Variants are what a shopper actually buys. Each has an id, a sku, its stock and whether it is shippable. Add a variant to a cart by its id or its sku.
  • Options describe how variants differ, such as Colour or Size. A product's options list the options its live variants use, in the merchant's order, each with the values in use. Each variant's own options name its value per option. That is all an option picker needs.
  • Collections group products. They nest: each has a parent_id, and may list its children.
  • Attributes are the merchant's own product fields, such as brand or material. Filterable attributes can narrow a listing with filter[attr].
  • Images have a url and a thumbnail_url.
  • Prices are per variant, as money objects.

A product

GET /v1/products/oak-desk-lamp (trimmed)
{
  "data": {
    "id": 101,
    "status": "published",
    "name": "Oak desk lamp",
    "description": "Turned solid oak base with a linen shade.",
    "slug": "oak-desk-lamp",
    "options": [
      { "id": 3, "handle": "finish", "name": "Finish", "label": "Finish",
        "values": [{ "id": 7, "name": "Natural" }, { "id": 8, "name": "Smoked" }] }
    ],
    "variants": [
      {
        "id": 1543,
        "sku": "LAMP-OAK-NAT",
        "stock": 12,
        "shippable": true,
        "price": { "amount": 8900, "currency": "GBP", "formatted": "£89.00" },
        "pricing": {
          "price": { "amount": 8900, "currency": "GBP", "formatted": "£89.00" },
          "sale_price": null,
          "compare_price": null,
          "on_sale": false,
          "saving": null,
          "badges": []
        },
        "options": [{ "option_id": 3, "option": "Finish", "value_id": 7, "value": "Natural" }]
      }
    ],
    "images": [
      { "id": 55, "name": "oak-desk-lamp", "url": "https://…/oak-desk-lamp.webp", "thumbnail_url": "https://…/oak-desk-lamp-thumb.webp" }
    ],
    "collections": [{ "id": 4, "parent_id": null, "name": "Lighting", "slug": "lighting" }],
    "offers": []
  }
}

GET /v1/products/{slug} always returns the full product, whatever you pass in include. Listings return only what you ask for.

Prices on a variant

FieldMeaning
pricing.priceThe price for one unit. price on the variant is the same amount, kept for older clients.
pricing.sale_priceThe promotional sale price, when a catalogue sale applies and the store shows sale prices. Otherwise null.
pricing.compare_priceThe merchant's "was" price, only when it is above the price.
pricing.on_saleWhether to present the item as on sale.
pricing.savingWhat a promotion saves, as amount and percent_bp (basis points).
pricing.badgesBadges to show, each with a label and kind.

When the request carries a signed-in customer's bearer token, prices are that customer's customer-group prices. Otherwise they are the default prices a guest sees.

List products

curl -G https://api.elaraone.app/api/v1/products \
  -H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
  -H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
  --data-urlencode "filter[collection]=lighting" \
  --data-urlencode "filter[price_max]=10000" \
  --data-urlencode "sort=-price" \
  --data-urlencode "include=variants.prices,images" \
  --data-urlencode "perPage=24"

Filters

ParameterExampleMatches
filter[collection]filter[collection]=lightingProducts in the collection with this slug
filter[search]filter[search]=mugProducts whose name contains the text, ignoring case
filter[price_min]filter[price_min]=2000Products with a variant priced at or above this, in integer minor units
filter[price_max]filter[price_max]=5000Products with a variant priced at or below this, in integer minor units
filter[attr][handle]filter[attr][material]=linenProducts whose attribute has this value, ignoring case. Repeat for more attributes; they all have to match.

Filters combine: every one you send has to match. filter[search] is a simple name match. For ranked, typo-tolerant search with facets, use search.

Sorts

sort takes one of name, created_at or price. Put - in front for descending order, for example sort=-created_at for newest first or sort=price for cheapest first.

Includes

include takes a comma-separated list:

IncludeAdds
variantsThe variants, without prices
variants.pricesEach variant's price and pricing
variants.optionsThe product's options and each variant's options
imagesThe product's images
collectionsThe collections the product is in
offersThe promotions the product advertises, for badges, banners and bulk-price tables

Ask only for what the page shows: a listing grid usually needs variants.prices,images.

An unknown filter, sort or include is refused with 400.

Pages

perPage sets the page size, from 1 to 100 (default 24), and page picks the page. Responses carry links and meta. See pagination.

Price bounds

GET /v1/products/price-bounds returns the price range of the products a listing would show with the same filter[collection], filter[search] and filter[attr]. Forward your listing's query string unchanged: filter[price_min] and filter[price_max] are accepted but ignored, so the slider's range never shrinks to the range the shopper just picked.

Response
{
  "data": {
    "currency": "GBP",
    "min": { "amount": 1800, "currency": "GBP", "formatted": "£18.00" },
    "max": { "amount": 8900, "currency": "GBP", "formatted": "£89.00" }
  }
}

Promotions

GET /v1/promotions lists the store's live public offers, unpaginated, for an offers strip or banners.

Response (trimmed)
{
  "data": [
    {
      "id": 12,
      "kind": "free_shipping",
      "label": "Free delivery over £50",
      "badge": null,
      "banner": { "title": "Free delivery over £50", "body": "On every order to the UK mainland." },
      "ends_at": "2026-11-30T23:59:59+00:00",
      "target": null,
      "scope": "all"
    }
  ]
}

kind is the rule kind: product_adjustment, cart_adjustment, bulk_tiered, bundle_set, buy_x_get_y or free_shipping. scope says what the rule covers: all (store-wide), collection or product.

Offers on a single product come back in its offers (always on GET /v1/products/{slug}, and on listings with include=offers). A bulk rule adds a bulk_table of quantity bands, each with min_qty, max_qty, unit_price and percent_bp.

Countries

GET /v1/countries lists the countries the store sells and ships to. Use it to build the country picker in address forms: the country's id is the country_id that cart and account addresses take.

Response (trimmed)
{
  "data": [
    { "id": 235, "iso2": "GB", "iso3": "GBR", "name": "United Kingdom", "phonecode": "44" }
  ],
  "meta": { "default_country": "GB" }
}