Skip to main content
@opencals/storefront-sdk is the official type-safe TypeScript client for the Storefront API. It’s generated from the same OpenAPI specification as the API reference, so every request and response is fully typed, and it ships with Zod schemas for runtime validation plus formatting helpers for prices, durations, and timezones. MIT licensed.

Installation

npm install @opencals/storefront-sdk

Setup

Call setupOpencals() once at app startup — a root layout, an API client singleton, or a module you import from your server code:
import { setupOpencals } from "@opencals/storefront-sdk";

setupOpencals({
  apiKey: "sfk_…",          // or set the OPENCALS_API_KEY env var
  baseUrl: "https://…",     // optional, defaults to https://api.opencals.com
  logging: true,            // optional request/response logging
  errorHandler: true,       // throw OpencalsApiError on failures (default)
  customerToken: "eyJ…",    // optional customer JWT for authenticated requests
});
With the OPENCALS_API_KEY environment variable set, setupOpencals() needs no arguments.
The API key is attached to every request automatically — which also means SDK calls belong on the server, where the key is safe.

Services

The SDK mirrors the API’s tags as static service classes:
ServiceMethods
ProductServicelist, get, getBySlug, getByExternalId, getCurrentAvailabilities, getCurrentAvailabilitiesMerged, getNearestAvailability
AuthServicesignIn, signUp, oauth, refresh, requestPasswordReset, resetPassword, requestEmailVerification, verifyEmail
CartServiceget, createOrGet, addItem, removeItem, extendExpiration, applyDiscountCode, removeDiscountCode
CheckoutServicestart, submit, saveCustomer, saveAnswers, getCartQuestions
AppointmentServicelist, find, create, cancel, reschedule, feedback, getBookingPreferences
OrderServicelist, find
SelfServicegetProfile, updateProfile, changePassword
LocationServicelist, get, getBySlug
StaffMemberServicelist, getBySlug
PaymentServicegetAvailableProviders, getSettings
StoreServicegetStorePublicSettings
ProductCollectionServicelist, getBySlug
ImageServiceget
CheckoutQuestionServicelistTranslations
FeedbackQuestionServicelistTranslations
Every method takes a single options object with typed path, query, body, and headers fields matching the underlying endpoint:
import { ProductService } from "@opencals/storefront-sdk";

// GET /storefront/products/slug/{slug}
const { data: product } = await ProductService.getBySlug({
  path: { slug: "haircut" },
});

// GET /storefront/products/{productId}/current-availabilities
const { data: slots } = await ProductService.getCurrentAvailabilities({
  path: { productId: product!.id },
  query: { date: "2026-06-15", timezone: "America/New_York" },
});
Cart and checkout calls pass the cart ID through the typed headers field:
import { CartService } from "@opencals/storefront-sdk";

const { data: cart } = await CartService.createOrGet({
  headers: { "X-Cart-Id": cartId ?? "" },
});

await CartService.addItem({
  body: { appointmentId },
  headers: { "X-Cart-Id": cart!.id },
});

Customer-authenticated requests

For endpoints that act on behalf of a signed-in customer, either pass customerToken to setupOpencals() or set the header per call:
import { AppointmentService } from "@opencals/storefront-sdk";

const { data: appointments } = await AppointmentService.list({
  headers: { Authorization: `Bearer ${accessToken}` },
});
See Authentication for how to obtain and refresh customer tokens.

Error handling

With the default error handler enabled, failed requests throw a typed OpencalsApiError:
import { OpencalsApiError, ProductService } from "@opencals/storefront-sdk";

try {
  await ProductService.get({ path: { productId: "missing" } });
} catch (error) {
  if (error instanceof OpencalsApiError) {
    console.error(error.message);
  }
}

Zod validation

Response types come with auto-generated Zod schemas, useful when data crosses a trust boundary (for example, after passing through your own API routes):
import { zProductListResponse } from "@opencals/storefront-sdk";

const result = zProductListResponse.safeParse(apiResponse);

Helpers

The SDK includes small utilities you’d otherwise rewrite in every booking UI:
import {
  formatPrice,
  formatDuration,
  toLocalFromUtc,
  toUtcFromLocal,
  mergeTimeIntervals,
} from "@opencals/storefront-sdk";

formatPrice(4500, "USD");                              // "$45.00"
formatDuration(3600);                                  // "1h"
toLocalFromUtc("2026-06-15T14:00:00Z", "America/New_York");
toLocalFromUtc / toUtcFromLocal handle the UTC conversion the API expects for appointment slots, and mergeTimeIntervals is handy when rendering availability ranges.

Putting it together

The Build a booking page tutorial uses the SDK end-to-end — services, availability, cart, and checkout — and the open-source booking templates are complete Next.js apps built on it.
Last modified on June 21, 2026