---
title: Catalog hook
description: Load complete Lockerverse widget data without loading Stripe or payment UI.
sidebar:
  order: 1
---

```tsx
import { useLockerverseWidget } from "@lockerverse/react/widget";
```

## Input

```ts
type CreateLockerverseWidgetOptions = {
  communitySlug: string;
  widgetSlug: string;
  requestTimeoutMs?: number;
  sentryDsn?: string | null;
  fetch?: typeof globalThis.fetch;
  onError?: (error: LockerverseSdkError) => void;
} & (
  | { apiBaseUrl: string; environment: "development" | "production" }
  | { apiBaseUrl?: undefined; environment?: "production" }
);
```

## Result

```ts
type UseLockerverseWidgetResult = {
  catalog: LockerverseCatalog | null;
  client: LockerverseCheckoutClient;
  error: Error | null;
  loading: boolean;
  refresh: () => void;
};
```

The loaded catalog includes an optional event:

```ts
type LockerverseEvent = {
  description: string | null;
  endAt: string;
  id: string;
  location: string | null;
  name: string;
  startAt: string;
  status: "draft" | "active" | "finished" | "cancelled";
};

type LockerverseCatalog = {
  event: LockerverseEvent | null;
  products: LockerverseProduct[];
  // Community, payment, pricing policy, and widget configuration are also present.
};
```

`startAt` and `endAt` are event timestamps. Use `status` to determine the
event lifecycle state.

## Product interface

```ts
type LockerverseProduct = {
  id: string;
  listingId: string;
  slug: string;
  name: string;
  description: string | null;
  fulfillmentType: "none" | "event_admission";
  pricingMode: "fixed" | "custom";
  paymentOption: "one-time" | "monthly" | "annually";
  amountCents: number | null;
  minimumAmountCents: number | null;
  minimumQuantity: number | null;
  maximumQuantity: number | null;
  inventoryQuantity: number | null;
  acceptsDiscounts: boolean;
};
```

An `event_admission` Product is fulfilled by the catalog event.

The hook treats all options as initialization values and keeps one client for
its mounted lifetime. `refresh()` requests that same widget again. To use a
different widget, remount the component that owns the hook with a new React
`key`. Selection and other view state can change without a remount. This entry
does not import Stripe or payment UI.

## Reuse the loaded catalog

```tsx
const widget = useLockerverseWidget(options);

<LockerversePayment
  selection={selection}
  widget={widget}
/>
```

The hook result carries its catalog and client. The host can calculate
selection totals from the catalog while the payment component uses that client to request the
current, authoritative quote. The payment form mounts immediately with a local
estimate. The authoritative quote replaces that estimate in the background
before payment confirmation.
