@behio/storefront-sdk

中文文档
2.32.0发布于 2026/11/07MITTypeScriptESM + CJS零依赖近 30 天下载 2040

TypeScript SDK for Behio headless e-commerce: core client + React hooks

原始使用文档
文档目录28 节
  1. Catalog display settings (2.9.0)
  2. Why Behio?
  3. Install
  4. Quick Start
  5. Websites without a shop (2.17.1)
  6. Product resources and variant pages
  7. React Hooks
  8. What's Included
  9. SDK Modules
  10. React Hooks (30+)
  11. FAQ content (2.21.0)
  12. Withdrawal from contract (2.25.0)
  13. Bookings (2.24.0)
  14. Framework Support
  15. Built-in Features
  16. Documentation
  17. License
  18. Checkout price review and merchant policies
  19. Canonical discovery URLs
  20. Catalog availability and price privacy
  21. Complete category filters
  22. One of a kind (2.5)
  23. Cart links from Behio Chat (2.4)
  24. Form validation errors (2.6.1)
  25. Cart summary for page scripts (2.6)
  26. Bundle offers and galleries (2.0, unreleased)
  27. Retained product rows (2.0, unreleased)
  28. Customer rewards (2.9)

@behio/storefront-sdk

Headless e-commerce SDK for building custom storefronts.

Behio gives you a complete e-commerce backend (products, inventory, orders, customers, discounts, multi-currency, multi-language) and lets you design the storefront however you want. Merchants run on it worldwide, with local tax rules, carriers and payment gateways handled natively. No themes, no templates, no vendor lock-in.

Catalog display settings (2.9.0)

ShopInfo.defaultProductSort carries the normalized merchant default. Use it for the selected sort control when the URL does not specify a sort. Omitting sort from a catalog request applies this default on the server.

Price bounds and facet ranges use the visitor's displayed offer, including customer pricing and variant starting prices. Use the same authenticated client for both calls. When guest prices are hidden, the range is null and price bounds are ignored to prevent disclosure through result counts.

ProductLabel and FacetLabel expose nullable iconName alongside the merchant's color and localized name. Product lists, details, labels and facets preserve this value. Render a trusted local icon with a safe fallback; never treat the string as SVG, HTML or a URL. Labels and automatic rules are resolved by the API. Keep text visible and use readable contrast for the chosen color.

Why Behio?

  • You own the frontend. Next.js, React, Vue, Nuxt, Astro, or plain JS, the backend doesn't care.
  • Production-ready in minutes. Catalog, cart, checkout, customer accounts, orders, CMS, discount codes, gift cards, loyalty programs, and more.
  • Built for developers. Full TypeScript types, auto-completing, modern React hooks with TanStack Query.
  • Scale-ready. Redis caching, rate limiting, webhooks, atomic checkout (no double-spend, no overselling).

Install

React cart mutations in 2.0.1 cancel older cart reads before writing and before accepting the server response. This includes adding, clearing, applying or removing a discount, and merging baskets. A delayed read cannot restore an old basket after one of those actions succeeds.

From 2.0.3, responses and retries from an older customer, cart session, currency, country or locale are rejected with SDK status 409. Retry explicitly in the current context. An ordinary token refresh remains in the same customer session. useAuth() cancels old queries and removes customer data and prices on an identity change, including seeded SSR data. A late logout or failed refresh cannot clear a newer login. This browser protection does not replace per-request SSR clients or server authorization.

npm install @behio/storefront-sdk

Quick Start

import { BehioStorefront } from '@behio/storefront-sdk';

const storefront = new BehioStorefront({
  apiKey: 'pk_live_your_key',
});

// Fetch products and check the typed result.
const products = await storefront.catalog.getProducts({limit: 12});
if (products.error || !products.data.items.length) throw new Error('No products available');
await storefront.cart.addItem({productId: products.data.items[0].id, quantity: 1});

// After the customer enters addresses and selects shipping/payment:
const previewResult = await storefront.checkout.preview(checkoutInput);
if (previewResult.error) throw new Error(previewResult.error.message);
// Render previewResult.data.grandTotal. Wait for the customer to submit.
const orderResult = await storefront.checkout.createOrder({
  ...checkoutInput,
  previewToken: previewResult.data.previewToken,
});
if (orderResult.error) throw new Error(orderResult.error.message);
// Redirect to paymentRedirectUrl, or display the receipt for orderResult.data.

Websites without a shop (2.17.1)

Every Behio storefront belongs to a site. A site starts as a website: shop info, SEO, pages, blogs, FAQ, forms, collections and analytics work with its key, and categories and featured products return empty lists. The other shop endpoints (products, cart, checkout, customer accounts, orders) answer 404 with the code be.storefront.siteKeyNotAllowed until the merchant adds a shop to the website, in the Behio admin or with the MCP tool site-commerce-enable. From then on the same key and the same site id serve the shop too, and the shop shares the website's name, languages, logo, appearance and SEO.

import { errorCode } from '@behio/storefront-sdk';

const {data, error} = await storefront.catalog.getProducts({limit: 12});
if (errorCode(error) === 'be.storefront.siteKeyNotAllowed') {
  // Website without a shop: hide the shop navigation instead of an error page.
}

errorMessage(error, locale) returns a translated sentence for this code in cs, sk and en.

Paid orders may briefly return contentDeliveryPending: true while purchased files and course access are being assigned. Render this state in the initial receipt HTML and refresh the authenticated order detail until it clears. Tell the customer that payment was received and that they do not need to place a second order. Existing downloads remain usable while other content is pending. Behio stores this work with the payment transaction and retries interrupted or failed delivery after restart. Repeating delivery preserves access expiry, download counters and course progress.

Product resources and variant pages

Render resolveVariantContent(product, selectedVariant).assetGroups in the initial HTML. A variant with public resources replaces the parent's groups; an empty or absent array inherits them. Render every group and respect item order, localized titles and sanitized descriptions. Files are normal public links, images open at full size, uploaded videos use native controls, and external YouTube/Vimeo players load after an explicit click. Preserve Vimeo's unlisted privacy hash. These groups never contain purchased download URLs.

requiresShipping and isDigital belong to the selected variant. Use them for its delivery information; the cart remains authoritative for the whole order. catalogSiblings contains separate product pages: render real localized links and mark isCurrent, preserving the remaining axes in the variant picker. Disable values that have no purchasable variant; use isPurchasable so zero-stock BACKORDER options remain selectable. Clear incompatible axis selections.

Product reviews must also be present in the first HTML. Fetch page one on the server and pass it as initialData to useProductReviews; page and limit identify the cache entry. Use the selected variant's ID and own rating, render photos and merchant replies, and distinguish failures from an empty list. Verified purchase requires authenticated order ownership. A helpful vote with success: false is a duplicate; errors must roll back optimistic counts.

React Hooks

Catalog pricing supports a request-specific country alongside currency and customer authentication. new BehioStorefront({apiKey, country: 'SK', currency: 'EUR'}) resolves country rules on every catalog surface. setCountry() changes that default; explicit per-call country values win. It does not change the cart: use cart.setDestination() for that. The Next.js adapter reads behio_country for the initial server render. Keep authenticated responses private and include both currency and country in guest cache keys. When initializing a new cart, cart.setCurrency() and cart.setDestination() save its returned session before the next mutation. Templates should initialize this context before the first product or bundle is added, including after the previous cart expires.

import { BehioProvider, useProducts, useCart } from '@behio/storefront-sdk/react';

function App() {
  return (
    <BehioProvider apiKey="pk_live_your_key">
      <ProductList />
    </BehioProvider>
  );
}

function ProductList() {
  const { items, isLoading, error } = useProducts({ limit: 12 });
  const { addItem, isAdding } = useCart();

  if (isLoading) return <div>Loading...</div>;

  if (error) return <p role="alert">Products could not be loaded.</p>;

  return items.map(p => (
    <div key={p.id}>
      <h3>{p.name}, {p.price ? `${p.price.amount} ${p.price.currency}` : "Sign in to view price"}</h3>
      <button disabled={isAdding || !p.isPurchasable} onClick={() => addItem(p.id, 1).catch(() => window.alert("The item could not be added."))}>
        Add to Cart
      </button>
    </div>
  ));
}

The example above shows browser hook usage. Production templates render the initial catalog/cart on the server and hydrate their data. HTTP-only sessions stay behind Server Actions or a session-bound API. useCart() returns cart, isEmpty, itemCount and its mutation methods. Update/removal retain the last complete server snapshot while pending and accept the entire successful response, even when query fetching is disabled. Failed writes do not roll back newer cache values. isEmpty includes bundle lines; itemCount uses server bundle quantities. The provider notifies hooks after restoring browser session storage.

What's Included

SDK Modules

ModuleDescription
catalogProducts, categories, labels, search, filters, bundles, cross-sell, promotions
authRegister, login, logout, password reset, token refresh
cartItems, discounts, gift cards, bundles, cart merge
checkoutPreview the final total and create orders with a signed price review
ordersList, detail, tracking, cancel
customerProfile, addresses, password change
wishlistAdd, remove, check
reviewsSubmit, list, vote helpful
addressesAddress autocomplete with debounce hook
shippingList shipping methods and fetch live carrier quotes (Zaslat.cz + extensible)
returnsSubmit return requests
consentCookie consent (GDPR)
quotesB2B quote requests
pagesCMS pages
faqFAQ groups and visible questions in the requested language (web + e-shop)
blogBlogs and published posts (web + e-shop)
formsMerchant-defined forms: definition + validated submit with per-field errors (web + e-shop)
bookingsOnline appointments: services and staff, free times, create, change and cancel by token (web + e-shop)

React Hooks (30+)

useProducts · useProduct · useCategories · useFeatured · useLabels · useSearch · useFilters · useBundles · useBundle · useCrossSell · useProductPromotions · useGiftCardBalance · useCart · useCheckout · useOrders · useOrder · useCustomer · useAddresses · useAddressAutocomplete · useWishlist · useProductReviews · useSubmitReview · useShopInfo · useShopSeo · useCartCount · useBlogs · useBlogPosts · useBlogPost · useSiteForm · useSiteFormSubmit

FAQ content (2.21.0)

Read FAQ groups configured for the site in the Behio admin. A group can be addressed by its slug or ID. Hidden questions are excluded; missing translations fall back to the site's default language. An unknown group returns a 404 error.

const groups = await storefront.faq.list({locale: 'cs'});
if (groups.error) throw new Error(groups.error.message);

const delivery = await storefront.faq.get('delivery', {locale: 'cs'});
if (delivery.error) throw new Error(delivery.error.message);
// delivery.data.items contains questions and sanitized HTML answers in admin order.

React clients can use useFaqGroups({locale}) and useFaqGroup(slugOrId, {locale}) from @behio/storefront-sdk/react within BehioProvider. For SEO, include the questions in server-rendered HTML and emit one FAQPage JSON-LD object containing only the questions actually visible on that page.

Withdrawal from contract (2.25.0)

EU law (Art. 11a Directive 2011/83/EU, from 19 Jun 2026) requires an online withdrawal function for consumer purchases. When shopInfo.withdrawal.enabled, link it from the footer and the customer account with a clear label such as "Withdraw from contract here". The flow has two steps: a form (name, order number, e-mail), then a summary with a "Confirm withdrawal" button. Only the confirmation calls withdraw; show the returned acknowledgement, the same content with date and time goes out by e-mail.

const {data: order} = await storefront.returns.lookupOrder('B-2026-0042', '[email protected]');
// order.customerName prefills the name, order.withdrawal tells the period and flags
const {data: ack, error} = await storefront.returns.withdraw({
  orderNumber: 'B-2026-0042',
  email: '[email protected]',
  name: 'Jana Nováková',
  confirmed: true, // the consumer pressed "Confirm withdrawal"
});
// ack.submittedAt, ack.items, ack.confirmationSent

Bookings (2.24.0)

Online appointments from the Behio Bookings module. Days are YYYY-MM-DD in the branch time zone (config.timezone); a taken time answers 409 be.bookings.slotTaken, so reload free times and let the customer pick again.

const {data: config} = await storefront.bookings.getConfig();
const {data: free} = await storefront.bookings.getSlots({serviceIds: [config.services[0].id], from: '2026-10-21', to: '2026-11-03'});
const {data, error} = await storefront.bookings.create({serviceIds: [config.services[0].id], startMs: free.slots[0].startMs, name: 'Jana', email: '[email protected]', website: ''});
// data.booking.code, data.booking.status ('CONFIRMED' or 'PENDING'), data.manageToken

Change and cancel by the token from the confirmation email: getByToken, getManageSlots, reschedule, cancel. React: useBookingConfig, useBookingSlots, useCreateBooking, useManagedBooking, useCancelBooking, useRescheduleBooking. Without your own UI, embed the hosted widget instead (see the Bookings page of the docs).

Framework Support

  • Next.js: Server components + client hooks, SSR ready
  • React + Vite: Standard SPA setup
  • Nuxt 3: Composables with SSR
  • Vue + Vite: Provide/inject pattern
  • Vanilla JS: Works in any runtime (Node.js, Deno, Bun, Cloudflare Workers)

Built-in Features

  • Automatic JWT token refresh on 401
  • Configurable retry with backoff (5xx, 429)
  • Rate limit tracking and warnings
  • Request/response interceptors
  • Event system (auth, cart, order lifecycle)
  • Cart session persistence

Documentation

Full API reference, framework guides, and examples:

sdk.behio.com

License

MIT

Checkout price review and merchant policies

Call checkout.preview(input) after the shopper completes delivery and payment choices. Render its grandTotal, then send its previewToken with the final createOrder input. The token lasts five minutes and is bound to the current cart, prices and choices. A changed or expired review returns be.storefront.checkoutChanged: refresh the display and wait for the shopper to submit again. useCheckoutPreview is available for React; Server Actions are preferred when storing the guest receipt token in an HttpOnly cookie.

discountTotal includes loyalty and gift-card deductions. Receipt snapshots add paymentFee, roundingAdjustment, loyaltyDiscount, and giftCardDeducted; null denotes an older order. Never double-subtract a breakdown. Use cart.checkoutLimits for min/max values in cart currency. Checkout flags, account/password policy, appearance, maintenance, SEO and currency display come from the typed shop contract. See the checkout documentation for independent legal consents and the exact preview lifecycle.

Physical delivery uses product.requiresShipping and cart.requiresShipping, independently of downloadable bonuses. Online-only orders need a billing address and omit shipping. CourseListItem.isRevoked and DigitalDownload.isRevoked distinguish withdrawn access from expiry. Course purchases have independent access periods; retries do not extend access, and refunding one purchase preserves another valid purchase.

Delivery progress uses Cart.shippingSubtotal, after product promotions and before order coupons/loyalty/gift cards. shippingPromotionApplied marks an active free-delivery promotion. Method thresholds already include the shop-wide threshold converted into the requested currency. Online carts (requiresShipping: false) have no delivery progress.

Guest course purchases are linked to an account only after its email address is verified, even when email verification is optional for registration. Purchases made while authenticated belong to that account. A different checkout receipt email cannot claim another account’s courses. Unverified accounts cannot extend their access using guest purchases sent to the same address. Render a verification notice for unverified customers in the course area without revealing guest purchases.

Show customer cancellation only for an owned PENDING and UNPAID order. The backend checks both states while holding the order lock; payment can change after the page loads, so keep a visible error and refresh the order after rejection. Cancellation restores the actual remaining stock deduction once. Warehouse allocation identifiers are internal and must never be rendered by a template.

Canonical discovery URLs

catalog.getSitemap(locale?) follows canonical variant indexing and bound-domain product selection. Its entries and ProductDetail.seo expose optional localizedSlugs in 1.20, mapping enabled languages to actual canonical slugs. Use those for hreflang and language links; omit unknown translations instead of inventing them. Crawler clients must be sessionless. In Next metadata routes, call connection() before dynamic SDK fetches and verify a production build.

Catalog availability and price privacy

A failed price entitlement lookup returns HTTP 503 with be.storefront.pricingUnavailable; unrestricted guest pricing is never a fallback. With throwOnAvailabilityError: true, catch known SDK availability exceptions only where an explicit server-rendered error and retry replace the failed content. A {data, error} check alone cannot handle that exception path. Never treat an outage as zero reviews, zero products, a free offer, or a 404.

Complete category filters

catalog.getCategoryProducts(slug, query) shares the full ProductsQuery serializer with getProducts. Price bounds retain zero, boolean filters retain false, arrays use repeated parameters and public parameter/facet selections use JSON. Category, main-list and featured availability follow the same published-variant and stock-mode rules in the backend.

One of a kind (2.5)

ProductListItem.isUnique marks a handmade original: one piece, never restocked, never sold beyond stock. soldAt is set once it sells and the availability label reads "Sold". Hide quantity steppers, never offer back-in-stock watching for originals, offer "I want a similar one" instead.

cart.claimLink(token) adds the products of a prepared cart link (created by the AI in Behio Chat) to the visitor's cart and applies the link's discount code. Call it on the server in a /cart/link/[token] route handler, then redirect to checkout. Items are added, never replacing the cart; a second open does not double quantities. Expired links fail with be.storefront.cartLinkExpired. Answer GET /cart/link/_probe with header x-behio-cart-link: 1 so Behio Chat knows the storefront supports links.

Form validation errors (2.6.1)

formFieldErrors(error) retains every supported field code, including dateNotFuture, dateNotPast and tooManyFiles. Display each error beside its field and preserve entered values when a submission is rejected.

Cart summary for page scripts (2.6)

Browser cart responses dispatch behio:cart on window with {total, currency, itemCount} and keep the last value in window.__behioCart (Behio Chat reads it for cart-value greetings). Carts with totalsAvailable: false, failed reads and changed customer/pricing context clear the last value and dispatch detail: null. Null means unknown, whereas {total: 0, itemCount: 0, currency} is a confirmed empty cart. Listeners must handle both. The count comes from the authoritative cart.itemCount, including bundle units. Older responses cannot restore a newer summary. Storefronts that mutate the cart on the server (Server Actions, snapshot routes) call publishCartSummary({total, currency, itemCount}) on the client after each fresh cart. Call clearCartSummary() when that snapshot fails, has unavailable totals or requires login. Both functions do nothing during SSR. Behio Chat cancels cart-value greetings and removes stale cart text when the value clears.

Bundle offers and galleries (2.0, unreleased)

catalog.getBundles({locale, currency, country}) and getBundle(slug, options) return explicit priceHidden, isPurchasable and unavailableReason alongside nullable prices and savings. Never render a null price as zero. Honor quantityRules.minimum, step and nullable maximum for additional complete sets in the current visitor basket. The server accounts for component steps, ordinary rows, other bundles, shared stock and merchant limits. Bundle list/detail requests carry the cart session and customer, return private no-store data, and must not enter shared caches. Hidden stock does not expose a numerical ceiling. React bundle hooks accept the same context plus server initialData and separate query caches by that context. They wait for session restoration; cart and auth hooks refresh their ranges after basket or identity changes. Direct core bundle mutations need cart refresh plus cancellation/invalidation of both bundle query prefixes. API errors require a retry state; they are not an empty catalog.

Merge a product's listing images with its shared media and deduplicate safe URLs. A shared video must not hide additional listing photos. Render the image links in the first HTML, then enhance thumbnail selection and native video.

Bundle checkout previews resolve the current explicit currency offer and component rules. Submit the preview token with the confirmed order; handle checkoutChanged by showing a new preview. Pending orders hold the bundle quota, terminal cancellation/refund releases it, and reopening must claim it again. Stock modes ALWAYS_AVAILABLE and MADE_TO_ORDER override saved tracked-stock limits throughout cart, checkout and order transitions, while retaining exact inventory movements.

Cart bundle lines return the current offer in the legacy-named bundlePriceSnapshot field. Stored cart and order snapshots are unchanged by a read. Show priceChanged and use quantityControls.decreaseTo / increaseTo for exact resulting whole-set quantities; null disables that direction. Keep server validation errors next to the row. Older servers can omit these controls. Native server-bound quantity/remove forms work before hydration. Bundle components keep their own tax rates and their allocated price participates in coupon targeting; cart reads recheck coupon eligibility after merchant or cart changes.

Version 2 changes bundle catalog prices and CartBundleLine.bundlePriceSnapshot to nullable values. Update consumers before upgrading: null is unavailable, never a free offer. An invalid bundle stays in the cart with isPurchasable: false and an unavailableReason; keep its remove control. QUANTITY_UNAVAILABLE may be repairable by changing the quantity. When cart.totalsAvailable === false, hide monetary totals and disable checkout in both cart and mini cart. Do not interpret the remaining numeric summary fields as a payable quote. The server rechecks component publication, sale windows, quantity, stock and domain selection before a bundle mutation. The SDK retains the session returned when an anonymous visitor first adds a bundle, so subsequent reads address the same cart.

Retained product rows (2.0, unreleased)

SDK 2 sends X-Behio-Cart-Contract: 2 on every cart request. This opts into nullable current prices. On the same v1 route, clients without this header retain numeric, same-currency stored price snapshots when the current offer disappears. That compatibility projection is not purchase authorization: preview and checkout always validate the current offer. An old client still needs upgrading to display the new availability and repair controls. Snapshots never bypass hidden-price authentication or relabel a foreign currency.

A product row also reports isPurchasable and unavailableReason. Its unit, line and tax amounts, plus product.currentPrice, are nullable when there is no current currency price. Do not revive an old snapshot or show null as zero. Keep the row removable; cart.totalsAvailable applies to products and bundles.

Prefer item.quantityControls.decreaseTo and increaseTo for cart steppers. A null target disables that direction. These targets account for units of the same product inside bundles, other listings sharing its stock, merchant minima, step multiples and maximums. They can jump directly to a valid repair after a merchant edit. Existing fractional units keep their fraction when no merchant step is configured. The server validates the resulting basket before writing; show returned errors next to the native form and reread the authoritative cart.

Domain-bound availability is preserved in currency, destination, code, merge, and removal responses. Analytics must omit unknown amounts and must not emit a payable cart value when totalsAvailable is false.

Customer rewards (2.9)

Authenticated, SSR-safe customer.getGamification({badgesPage?, challengesPage?, limit?}) returns earned badges and challenges with separate pagination. customer.joinChallenge(challengeId) keeps enrollment idempotent; customer.refreshGamification() reconciles persisted activity. Use POST forms for these mutations and re-read rewards plus the loyalty balance on success. Errors must remain visible. No client-provided point amount or progress is accepted.

版本与发布记录

@behio/storefront-sdk 共发布 103 个版本,首次发布于 2026/04/14;过去 12 个月发布了 103 个版本。

版本发布日期距今
2.32.0latest2026/11/071 天前
2.31.02026/11/071 天前
2.30.02026/11/071 天前
2.29.02026/11/061 天前
2.28.02026/11/062 天前
2.27.02026/11/062 天前

关于 @behio/storefront-sdk 的常见问题

@behio/storefront-sdk 是什么?

TypeScript SDK for Behio headless e-commerce: core client + React hooks

如何安装 @behio/storefront-sdk?

在项目目录运行 npm install @behio/storefront-sdk,或使用 pnpm add / yarn add / bun add。

@behio/storefront-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@behio/storefront-sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@behio/storefront-sdk 可以商用吗?

@behio/storefront-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@behio/storefront-sdk 的下载量有多少?

根据 npm 官方下载统计,@behio/storefront-sdk 在 2026/10/08 – 2026/11/06 这 30 天内被下载 2,040 次,日均约 68 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@behio/storefront-sdk 还在维护吗?

最新版本 2.32.0 发布于 2026/11/07(1 天前);至今共发布 103 个版本,其中过去 12 个月发布了 103 个;首次发布于 2026/04/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。