Behio Storefront SDK
Advanced

TypeScript Types

Complete type reference for the SDK

TypeScript Types

Complete reference of all types exported by @behio/storefront-sdk. All types are fully exported and can be imported directly:

import type { ProductDetail, Cart, CheckoutInput } from "@behio/storefront-sdk";

Configuration

BehioStorefrontConfig

interface BehioStorefrontConfig {
  /** API key (public: pk_live_xxx or private: sk_live_xxx) */
  apiKey: string;
  /** Backend base URL. Default: https://be.behio.com */
  baseUrl?: string;
  /** Default locale for catalog requests. Default: none (uses shop default) */
  locale?: string;
  /** Default currency for price resolution. Default: none (uses shop default) */
  currency?: string;
  /** Custom fetch implementation (for Node.js < 18 or testing) */
  fetch?: typeof fetch;
  /** Request timeout in milliseconds. Default: 30000 (30s) */
  timeout?: number;
  /** Number of retries on network/5xx errors. Default: 1 */
  retries?: number;
  /** Base delay between retries in ms (multiplied by attempt). Default: 1000 */
  retryDelay?: number;
  /**
   * Real visitor IP for server-side rendering, sent as X-Behio-Visitor-Ip so
   * the backend rate-limits per visitor instead of per rendering server. The
   * Next.js adapter fills this automatically from the request headers; only
   * trusted hosting IPs may set it, a browser sending it gains nothing.
   */
  visitorIp?: string | (() => string | null | undefined | Promise<string | null | undefined>);
}

Products

ProductListItem

Represents a product in list/collection views.

Popisy produktu jsou HTML

shortDescription i longDescription píše obchodník v rich text editoru v administraci, takže API vrací HTML (&lt;h3&gt;...&lt;/h3&gt;&lt;p&gt;...&lt;/p&gt;), nikdy holý text. Když je vypíšete jako {product.shortDescription}, React je zaescapuje a návštěvník uvidí doslova značky.

API obsah sanitizuje při čtení (allowlist: nadpisy, seznamy, odkazy, obrázky, tabulky; skripty, event handlery a javascript: odkazy jdou pryč), takže se dá vložit přes dangerouslySetInnerHTML. Šablony Behio na to mají komponentu RichText. Do meta description, JSON-LD, alt textů a jednořádkových popisků na kartách patří čistý text, ne HTML.

interface ProductListItem {
  id: string;
  slug: string;
  name: string;
  /** HTML z rich text editoru (sanitizované), ne holý text. */
  shortDescription?: string;
  sku: string;
  gtin?: string;
  price: ProductPrice;
  inStock: boolean;
  stockQuantity?: number;
  /** "Only X left". Non-null ONLY when the merchant enabled the nudge AND 0 < stock <= threshold. */
  lowStockRemaining?: number | null;
  /** Resolved availability (merchant preset or derived in-stock / sold-out), label localized. */
  availability: ProductAvailability;
  image?: string | null;
  labels: ProductLabel[];
  isFeatured: boolean;
}

ProductAvailability

interface ProductAvailability {
  /** Stable machine code: preset slug or derived 'in-stock' / 'sold-out'. */
  code: string;
  /** Localized display label, render as-is. */
  label: string;
  /** Optional merchant hex badge color. */
  color?: string | null;
  /** "Available from" date (epoch ms) for preorder-style states. */
  restockAt?: number | null;
}

ProductDetail

Full product detail, extends ProductListItem.

interface ProductDetail extends ProductListItem {
  /** HTML z rich text editoru (sanitizované), ne holý text. */
  longDescription?: string;
  images: Array<{ url: string; alt?: string; order: number }>;
  categories: Array<{ id: string; slug: string; name: string }>;
  variants: ProductVariant[];
  volumePricing: ProductVolumePrice[];
  /** Curated spec table. Array order is the display order; empty = render nothing. */
  parameterGroups: ProductParameterGroup[];
  seo: {
    title?: string | null;
    description?: string | null;
    keywords?: string | null;
  };
  productGroups?: Array<{
    slug: string;
    name: string;
    products: ProductListItem[];
  }>;
  /** Product weight (from warehouse item) */
  weight?: number | null;
  /** Weight unit: GRAM, KILOGRAM, TONNE */
  weightUnit?: string | null;
}

ProductPrice

interface ProductPrice {
  amount: number;
  currency: string;
  compareAtPrice?: number | null;
}

ProductVolumePrice

interface ProductVolumePrice {
  minQuantity: number;
  price: number;
  currency?: string;
}

ProductVariant

interface ProductVariant {
  id: string;
  sku: string;
  /** Localized name of this variant. */
  name: string;
  /**
   * Deep-link token, NOT a URL: a variant has no page of its own, so it lives at
   * `/product/{product.slug}?variant={variantSlug}`. Since SDK 1.1.0.
   */
  variantSlug: string;
  /** Own texts; null = inherit the parent's. HTML. Since SDK 1.1.0. */
  shortDescription?: string | null;
  longDescription?: string | null;
  /** Own gallery; empty = keep showing the parent's. Since SDK 1.1.0. */
  images: Array<{url: string; alt?: string; order: number; role?: string}>;
  /** Own SEO/OG overrides, null when none. Since SDK 1.1.0. */
  seo?: {
    title?: string | null;
    description?: string | null;
    keywords?: string | null;
    ogTitle?: string | null;
    ogDescription?: string | null;
    ogImage?: string | null;
  } | null;
  /** Axis name/value pairs, e.g. [{name: 'Barva', value: 'modrá'}]. */
  attributes: Array<{name: string; value: string}>;
  price: ProductPrice | null;
  inStock: boolean;
  stockQuantity?: number;
  /** "Only X left" for this variant, same contract as ProductListItem. */
  lowStockRemaining?: number | null;
  /** Variant's own spec table: own value where it has one, parent's elsewhere. */
  parameterGroups: ProductParameterGroup[];
}

ProductParameterGroup

One block of the merchant's curated spec table. Groups and parameters arrive in display order, there is nothing to sort by.

interface ProductParameterGroup {
  /** Derived from the merchant's own group name, stable, usable in URLs. */
  slug: string;
  /** Localized group heading, render as-is. */
  name: string;
  parameters: ProductParameter[];
}

ProductParameter

interface ProductParameter {
  /** Merchant-written label in the requested language. */
  label: string;
  /** Preformatted value. null ONLY for boolean parameters. */
  value: string | null;
  /** Non-null ONLY for boolean parameters, and then `value` is null. */
  booleanValue: boolean | null;
  /** Display unit: "cm", "g", a currency code, "%". null when the parameter has none. */
  unit: string | null;
}
/** Response of catalog.getProductParameters(slug, {locale}). */
interface ProductParametersResponse {
  groups: ProductParameterGroup[];
}

Parameters without a value are omitted server-side, so the array never contains an empty row. Warehouse data groups are not part of the public surface: no data-group id, no field key and no warehouse field type ever appears in a payload.

ProductLabel

interface ProductLabel {
  id: string;
  slug: string;
  name: string;
  color?: string;
}

ProductsQuery

Query parameters for listing products.

interface ProductsQuery {
  page?: number;
  limit?: number;
  /** Single category slug (OR logic with categories array) */
  category?: string;
  /** Multiple category slugs (OR logic) */
  categories?: string[];
  /** Single label slug */
  label?: string;
  priceMin?: number;
  priceMax?: number;
  currency?: string;
  locale?: string;
  sort?: ProductSortValue;
  inStock?: boolean;
  search?: string;
  /**
   * Parameter filters, keyed by parameter slug (FilterField.key / Facet.key).
   * Array = multi-select, OR within the key. Ranges use `<slug>_min` / `<slug>_max`.
   * Only parameters the merchant marked filterable are accepted.
   * e.g. { material: 'bavlna', barva: ['cerna', 'bila'], hmotnost_min: 100 }
   */
  parameters?: Record<string, unknown>;
  /**
   * Slug-based facet selection for SEO URLs: parameter slug -> value slugs,
   * e.g. { barva: ['cerna'] }. Resolved server-side to the underlying values.
   */
  facets?: Record<string, string[]>;
  /** Filter by specific product IDs */
  ids?: string[];
  /** Filter by specific product slugs */
  slugs?: string[];
  /** Multiple labels (AND logic, product must have ALL) */
  labels?: string[];
  /** Exclude specific product IDs */
  excludeIds?: string[];
  /** Exclude products in specific categories */
  excludeCategories?: string[];
  /** Only products with compareAtPrice (on sale) */
  hasDiscount?: boolean;
  /** Only featured products */
  isFeatured?: boolean;
  /** Products created after timestamp (epoch ms) */
  createdAfter?: number;
}

ProductSort

Available sort values (const object for runtime + autocomplete):

const ProductSort = {
  PRICE_ASC: "price_asc",
  PRICE_DESC: "price_desc",
  NAME_ASC: "name_asc",
  NAME_DESC: "name_desc",
  NEWEST: "newest",
  FEATURED: "featured",
} as const;

type ProductSortValue = (typeof ProductSort)[keyof typeof ProductSort];

FilterField

One filterable parameter, as returned by getFilters({locale}).

interface FilterField {
  /** Parameter slug. The key you send back in ProductsQuery.parameters. */
  key: string;
  /** Localized parameter label. */
  name: string;
  /** How to render the control, not how the value is stored. */
  type: "enum" | "range" | "boolean";
  /** Parameter group the field belongs to (same grouping as the spec table). */
  groupSlug: string;
  /** Localized group name. */
  groupName: string;
  /** Display unit next to the input: "cm", "g", "%", a currency code. */
  unit?: string | null;
  /** enum only: the selectable values, localized. */
  values?: string[];
}

Only parameters the merchant explicitly marked filterable are ever returned, so a visitor cannot filter by a field they cannot see on the product.


Categories

Category

interface Category {
  id: string;
  slug: string;
  name: string;
  description?: string;
  imageUrl?: string;
  children: Category[];
  productCount?: number;
}

CategoryDetail

Extends Category with SEO fields.

interface CategoryDetail extends Category {
  seoTitle?: string;
  seoDescription?: string;
}

Cart

Cart

interface Cart {
  id: string;
  sessionToken?: string;
  items: CartItem[];
  subtotal: number;
  discountTotal: number;
  discount?: CartDiscount;
  grandTotal: number;
  currency: string;
  itemCount: number;
}

CartItem

interface CartItem {
  id: string;
  product: CartItemProduct;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
  priceChanged: boolean;
  volumePriceApplied: boolean;
}

CartItemProduct

interface CartItemProduct {
  slug: string;
  name: string;
  sku: string;
  imageUrl?: string;
  inStock: boolean;
  currentPrice: number;
}

CartDiscount

interface CartDiscount {
  code: string;
  type: string;
  value: number;
}

AddToCartInput

interface AddToCartInput {
  /** Product ID (eshop product ID or warehouse item ID) */
  productId: string;
  quantity: number;
}

Checkout

CheckoutInput

interface CheckoutInput {
  shippingAddress: CheckoutAddress;
  billingAddress: CheckoutAddress;
  email: string;
  phone?: string;
  customerNote?: string;
}

CheckoutAddress

interface CheckoutAddress {
  firstName: string;
  lastName: string;
  company?: string;
  street: string;
  city: string;
  zip: string;
  country: string;
  phone?: string;
}

OrderDetail

Full order detail returned after checkout, extends OrderListItem.

interface OrderDetail extends OrderListItem {
  items: OrderItem[];
  shippingAddress: CheckoutAddress;
  billingAddress: CheckoutAddress;
  email: string;
  phone?: string;
  customerNote?: string;
  subtotal: number;
  taxTotal: number;
  shippingTotal: number;
  discountTotal: number;
  fulfillmentStatus: FulfillmentStatus;
  statusHistory: OrderStatusHistory[];
  trackingToken?: string;
}

Orders

OrderListItem

interface OrderListItem {
  id: string;
  orderNumber: string;
  status: OrderStatus;
  paymentStatus: PaymentStatus;
  grandTotal: number;
  currency: string;
  itemCount: number;
  createdAt: number;
}

OrderItem

interface OrderItem {
  productName: string;
  sku: string;
  imageUrl?: string;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
  totalPriceWithTax: number;
}

OrderStatusHistory

interface OrderStatusHistory {
  fromStatus?: OrderStatus;
  toStatus: OrderStatus;
  note?: string;
  changedBy?: string;
  createdAt: number;
}

Status enums

const OrderStatuses = {
  PENDING: "PENDING",
  CONFIRMED: "CONFIRMED",
  PROCESSING: "PROCESSING",
  SHIPPED: "SHIPPED",
  DELIVERED: "DELIVERED",
  CANCELLED: "CANCELLED",
  REFUNDED: "REFUNDED",
} as const;
type OrderStatus = (typeof OrderStatuses)[keyof typeof OrderStatuses];

const PaymentStatuses = {
  UNPAID: "UNPAID",
  PAID: "PAID",
  PARTIALLY_REFUNDED: "PARTIALLY_REFUNDED",
  REFUNDED: "REFUNDED",
} as const;
type PaymentStatus = (typeof PaymentStatuses)[keyof typeof PaymentStatuses];

const FulfillmentStatuses = {
  UNFULFILLED: "UNFULFILLED",
  PARTIALLY_FULFILLED: "PARTIALLY_FULFILLED",
  FULFILLED: "FULFILLED",
} as const;
type FulfillmentStatus = (typeof FulfillmentStatuses)[keyof typeof FulfillmentStatuses];

Auth

AuthTokens

interface AuthTokens {
  accessToken: string;
  refreshToken: string;
}

RegisterInput

interface RegisterInput {
  email: string;
  password: string;
  firstName?: string;
  lastName?: string;
}

LoginInput

interface LoginInput {
  email: string;
  password: string;
}

Customer

CustomerProfile

interface CustomerProfile {
  id: string;
  email: string;
  firstName?: string;
  lastName?: string;
  phone?: string;
  emailVerified: boolean;
}

CustomerAddress

interface CustomerAddress {
  id: string;
  type: AddressType;
  isDefault: boolean;
  firstName: string;
  lastName: string;
  company?: string;
  street: string;
  city: string;
  zip: string;
  country: string;
  phone?: string;
}

AddressType

const AddressTypes = {
  SHIPPING: "SHIPPING",
  BILLING: "BILLING",
} as const;
type AddressType = (typeof AddressTypes)[keyof typeof AddressTypes];

Bundles

Bundle

interface Bundle {
  id: string;
  slug: string;
  name: string;
  description: string | null;
  bundlePrice: number;
  currency: string;
  coverImage: string | null;
  endsAt: number | null;
  itemsSum: number;
  savings: number;
  savingsPercent: number;
  items: BundleItem[];
}

BundleItem

interface BundleItem {
  productId: string;
  slug: string | null;
  name: string;
  sku: string;
  quantity: number;
  imageUrl: string | null;
  defaultPrice: number | null;
}

Cross-sell

CrossSellItem

interface CrossSellItem {
  productId: string;
  slug: string | null;
  name: string; // localized
  sku: string;
  price: number | null; // in `currency`, incl. customer price-list override
  compareAtPrice: number | null; // original price when on sale
  currency: string;
  imageUrl: string | null;
  stockCached: number;
  inStock: boolean;
}

Promotions

ActivePromotion

interface ActivePromotion {
  id: string;
  name: string;
  slug: string;
  type: string;
  discountType: string;
  discountValue: number;
  startsAt: number;
  endsAt: number | null;
  badgeText: string | null;
  badgeColor: string | null;
  showCountdown: boolean;
  couponRequired: boolean;
}

Gift Cards

GiftCardBalance

interface GiftCardBalance {
  valid: boolean;
  balance: number;
  currency: string;
}

Wishlist

WishlistItem

interface WishlistItem {
  id: string;
  productId: string;
  productName: string;
  productSku: string;
  productSlug: string | null;
  imageUrl: string | null;
  price: number | null;
  stockCached: number;
  createdAt: number;
}

Reviews

ProductReviewsResponse

interface ProductReviewsResponse {
  items: ProductReview[];
  averageRating: number;
  reviewCount: number;
  page: number;
  totalPages: number;
}

ProductReview

interface ProductReview {
  id: string;
  authorName: string;
  rating: number;
  title: string | null;
  content: string | null;
  imageUrls: string[];
  isVerifiedPurchase: boolean;
  helpfulCount: number;
  unhelpfulCount: number;
  replyContent: string | null;
  createdAt: number;
}

SubmitReviewInput

interface SubmitReviewInput {
  productId: string;
  rating: number;
  title?: string;
  content?: string;
  authorName: string;
  authorEmail?: string;
  imageUrls?: string[];
}

Returns

ReturnRequest

interface ReturnRequest {
  id: string;
  orderId: string;
  status: string;
  reason: string;
  customerNote: string | null;
  refundAmount: number | null;
  refundMethod: string | null;
  createdAt: number;
}

SubmitReturnInput

interface SubmitReturnInput {
  orderId: string;
  reason: string;
  customerNote?: string;
  items: {
    orderItemId: string;
    productName: string;
    quantity: number;
    reason?: string;
    imageUrls?: string[];
  }[];
}

CookieConsent

interface CookieConsent {
  necessary: boolean;
  analytics: boolean;
  marketing: boolean;
  preferences: boolean;
  consentedAt: number;
}

CookieConsentInput

interface CookieConsentInput {
  visitorId: string;
  analytics: boolean;
  marketing: boolean;
  preferences: boolean;
}

Quotes (B2B)

QuoteRequest

interface QuoteRequest {
  id: string;
  status: string;
  contactName: string;
  contactEmail: string;
  companyName: string | null;
  quotedTotal: number | null;
  createdAt: number;
}

SubmitQuoteInput

interface SubmitQuoteInput {
  contactName: string;
  contactEmail: string;
  contactPhone?: string;
  companyName?: string;
  companyIco?: string;
  message?: string;
  items: {
    productId: string;
    quantity: number;
    requestedPrice?: number;
  }[];
}

Pages

Page

interface Page {
  slug: string;
  title: string;
  isActive: boolean;
}

PageDetail

interface PageDetail {
  slug: string;
  title: string;
  /** {format: "html", html: string} for HTML pages */
  content: unknown;
  seoTitle?: string;
  seoDescription?: string;
  /** Downloadable files (e.g. legal form PDFs), render as a download list */
  attachments: PageAttachment[];
}

interface PageAttachment {
  name: string;
  description: string | null;
  url: string;
  mimeType: string;
  fileSize: number;
}

Shop

ShopInfo

interface ShopInfo {
  id: string;
  name: string;
  domain: string;
  logo?: string;
  favicon?: string;
  isActive: boolean;
  defaultLanguage: string;
  supportedLanguages: string[];
  defaultCurrency: string;
  supportedCurrencies: string[];
  metaTitle?: string;
  metaDescription?: string;
  allowGuestCheckout: boolean;
  /** Shop runs in B2B / wholesale mode (unlocks B2B-oriented UX). */
  b2bMode: boolean;
  /** Whether quote requests make sense for this shop (currently follows B2B mode). */
  quotesEnabled: boolean;
}

ShopSeo

interface ShopSeo {
  locale: string;
  title: string | null;
  description: string | null;
  keywords: string | null;
  ogTitle: string | null;
  ogDescription: string | null;
  ogImage: string | null;
}

Errors

BehioApiError

Thrown for HTTP error responses from the API.

class BehioApiError extends Error {
  readonly code: BehioErrorCode;
  readonly status: number;
  readonly body: unknown;
  readonly isRetryable: boolean;

  constructor(status: number, body: unknown, message?: string);

  /** Check if this is a specific error type */
  is(code: BehioErrorCode): boolean;
}

BehioNetworkError

Thrown for network failures and timeouts.

class BehioNetworkError extends Error {
  readonly code: "NETWORK_ERROR" | "TIMEOUT";
  readonly isRetryable: true;

  constructor(message: string, isTimeout?: boolean);
}

BehioErrorCode

type BehioErrorCode =
  | "UNAUTHORIZED"
  | "FORBIDDEN"
  | "NOT_FOUND"
  | "VALIDATION_ERROR"
  | "CONFLICT"
  | "RATE_LIMITED"
  | "CART_EMPTY"
  | "PRODUCT_NOT_FOUND"
  | "INVALID_CREDENTIALS"
  | "INVALID_DISCOUNT"
  | "DISCOUNT_EXPIRED"
  | "TOKEN_EXPIRED"
  | "TOKEN_INVALID"
  | "EMAIL_ALREADY_EXISTS"
  | "ORDER_NOT_CANCELLABLE"
  | "INTERNAL_ERROR"
  | "NETWORK_ERROR"
  | "TIMEOUT"
  | "UNKNOWN";

Events

BehioEventType

type BehioEventType =
  | "auth:login"
  | "auth:logout"
  | "auth:token-refresh"
  | "auth:token-refresh-failed"
  | "cart:updated"
  | "cart:cleared"
  | "order:created"
  | "error"
  | "request"
  | "response"
  | "rate-limit-warning";

BehioEventHandler

type BehioEventHandler = (data?: unknown) => void;

Interceptors

RequestInterceptor

interface RequestInterceptorConfig {
  url: string;
  method: string;
  headers: Record<string, string>;
  body?: string;
}

type RequestInterceptor = (
  config: RequestInterceptorConfig,
) => RequestInterceptorConfig | Promise<RequestInterceptorConfig>;

ResponseInterceptor

interface ResponseInterceptorData {
  status: number;
  data: unknown;
  headers: Headers;
}

type ResponseInterceptor = (
  response: ResponseInterceptorData,
) => void | Promise<void>;

Pagination

PaginatedResponse

Generic wrapper for paginated list endpoints.

interface PaginatedResponse<T> {
  items: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}

MessageResponse

interface MessageResponse {
  message: string;
}

On this page