Behio Storefront SDK
Catalog & Products

Categories, Menu & Labels

Category tree, navigation menu, detail, and product labels

Categories

Category Tree

const { categories } = await client.catalog.getCategories('cs');
// Hierarchical tree with children

Category Detail

const category = await client.catalog.getCategory('electronics', 'cs');
// { id, name, slug, description, image, children }

Category Products

const {data: products, error} = await client.catalog.getCategoryProducts('electronics', {
  page: 1,
  limit: 12,
  sort: 'newest',
});

getCategoryProducts accepts the same ProductsQuery filters as getProducts: price bounds (including zero), stock, rating, search, labels, IDs, exclusions, parameters, facets and visitor locale/currency/country. Arrays remain repeated query parameters and parameter/facet selections are JSON. Invalid page zero is sent to validation instead of silently becoming page one. The route category remains the category scope.

Merchants build their storefront navigation in the admin under Navigace (Menu Builder). Fetch a resolved menu by its handle (the primary menu is "main"):

const { data: menu, error } = await client.catalog.getMenu('main', { locale: 'cs' });

if (error || !menu) {
  // 404 for an unknown or inactive handle. Fall back to the category tree.
  const { categories } = await client.catalog.getCategories('cs');
}

The response is a tree of items, each already resolved to a link target in the requested locale:

{
  "handle": "main",
  "name": "Hlavní menu",
  "locale": "cs",
  "items": [
    {
      "id": "01J...",
      "type": "CATEGORY",
      "label": "Elektronika",
      "description": null,
      "url": null,
      "ref": { "type": "CATEGORY", "slug": "elektronika" },
      "badgeText": "Sleva",
      "badgeTone": "SALE",
      "badgeColor": null,
      "badgeTextColor": null,
      "labelColor": null,
      "icon": "tag",
      "isHighlighted": true,
      "openInNewTab": false,
      "imageUrl": "https://.../tile.jpg",
      "children": [ /* same shape, up to depth 3 */ ]
    }
  ]
}

Item types and how to build the link:

typeLink target
CATEGORYyour category route, from ref.slug (e.g. /category/elektronika)
PAGEyour CMS page route, from ref.slug
PRODUCTyour product route, from ref.slug
COLLECTIONyour collection listing, from ref.slug
LINKitem.url verbatim (an arbitrary URL; ref is null)

For typed items (CATEGORY/PAGE/COLLECTION/PRODUCT) the target is ref, which resolves to { type, slug } at read time, so category, page and product renames flow through automatically without touching the menu. imageUrl is a processed tile image for mega-menu layouts. Inactive items and items whose target was deleted are skipped server-side, so you only ever render live links.

Item styling

Every node (including nested children) carries presentation fields the merchant sets in the admin. They are advisory: render what fits your template, ignore the rest, and defaults stay inert so an unstyled item looks exactly as before.

FieldTypeMeaning
badgeTextstring | nullChip label next to the item (e.g. "Novinka"). No chip when null.
badgeTone"NEUTRAL" | "SALE" | "NEW" | "ACCENT"Preset that maps to your palette. Always present. Suggested mapping: SALE to your sale color, NEW to a success color, ACCENT to your primary, NEUTRAL to the current text color.
badgeColorstring | nullCustom badge background hex. When set, it overrides badgeTone.
badgeTextColorstring | nullCustom badge text hex.
labelColorstring | nullCustom hex for the item label text. Null inherits your link color.
iconstring | nullA lucide icon slug (kebab-case, e.g. shopping-bag) to render before the label. Map it to your own icon set; unknown slugs render no icon.
isHighlightedbooleanEmphasize the item (bold or accent).
openInNewTabbooleanLINK items only: open the target in a new tab (target="_blank" rel="noopener"). Always false on typed items.

Custom hex colors are merchant-authored, so applying them via an inline style is the intended, legitimate use:

function MenuBadge({ item }: { item: MenuItem }) {
  if (!item.badgeText) return null;

  const custom = item.badgeColor || item.badgeTextColor;
  const toneClass = {
    NEUTRAL: 'badge--neutral',
    SALE: 'badge--sale',
    NEW: 'badge--new',
    ACCENT: 'badge--accent',
  }[item.badgeTone];

  return (
    <span
      className={custom ? undefined : toneClass}
      style={
        custom
          ? { backgroundColor: item.badgeColor ?? undefined, color: item.badgeTextColor ?? undefined }
          : undefined
      }
    >
      {item.badgeText}
    </span>
  );
}

// LINK items honoring the new-tab flag:
const linkProps = item.openInNewTab ? { target: '_blank', rel: 'noopener' } : {};

Labels

Labels are tags you can attach to products (e.g. "New", "Sale", "Bestseller"):

const { labels } = await client.catalog.getLabels('cs');
// [{ id, name, slug, color }]

Curated products highlighted by the admin:

const featured = await client.catalog.getFeatured({
  locale: 'cs',
  currency: 'CZK',
});

On this page