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

Setup

Call setupOpencals() once at app startup — a root layout, an API client singleton, or a module you import from your server code:
With the OPENCALS_API_KEY environment variable set, setupOpencals() needs no arguments.

Which API key

There is one key setting; the kind of key depends on where the SDK runs:
  • On a server (Next.js server components, route handlers, server actions, serverless functions): a private storefront key (spk_). It stays secret and can forward the buyer’s IP.
  • In the browser (embedded widgets, client-side apps): a public storefront key (sfk_) with allowed origins set to your domains. Don’t put a private key in browser code: anyone could read and reuse it. The SDK warns if you pass one there.
See API keys for details.

Forward the buyer’s IP

On a server, every SDK request comes from your server’s IP, so all your visitors share one rate-limit budget and abuse protection can’t tell them apart. Pass buyerIp, a function that returns the IP of the visitor a request is for, and the SDK sends it as X-Opencals-Buyer-Ip. With a private key the API then counts per visitor. Next.js apps use the ready-made resolver from @opencals/storefront-sdk/next:
lib/opencals.ts
nextBuyerIp reads x-real-ip, else the first x-forwarded-for entry (Vercel sets both on every request and overwrites what the browser sends). It forwards only on mutations (sign-in, cart, checkout), because reading request headers while rendering a GET would make cached pages dynamic. Outside a request it returns nothing. All the open-source templates use it. Other frameworks or proxies: pass your own function. It gets { method, url } and returns the visitor’s IP from the header your host sets (for example cloudfront-viewer-address on CloudFront), never from the request body:
  • The function runs for every request; return nothing to skip one.
  • A per-call headers: { "X-Opencals-Buyer-Ip": ip } takes precedence, and a function that throws never fails the request.
  • With a public key (sfk_) the header is ignored.
Available from SDK 0.3.19.

Services

The SDK mirrors the API’s tags as static service classes: Every method takes a single options object with typed path, query, body, and headers fields matching the underlying endpoint:
Cart and checkout calls pass the cart ID through the typed headers field:

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:
See Authentication for how to obtain and refresh customer tokens.

Error handling

With the default error handler enabled, failed requests throw a typed OpencalsApiError:
error.code carries the API’s machine-readable reason when there is one, for example CODE_EXPIRED or CODE_NOT_FOUND when a discount code is rejected (SDK 0.3.19+). error.toFieldErrors() flattens validation errors into { field: message } for forms.

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):

Helpers

The SDK includes small utilities you’d otherwise rewrite in every booking UI:
toLocalFromUtc / toUtcFromLocal handle the UTC conversion the API expects for appointment slots, and mergeTimeIntervals is handy when rendering availability ranges.

Examples

The Build a booking page tutorial walks through a full implementation, and the open-source booking templates are complete Next.js apps you can fork.
Last modified on October 24, 2026