Choose a real package source
The @hallify/sdk source package is provided at packages/sdk in the hallify.co repository, version 0.1.0. Install that directory with your package manager’s file dependency or use the versioned browser module route /sdk/0.1.0/browser/index.mjs after deployment. ESM JavaScript and TypeScript declarations are included; no SDK bundler build or React/Redux runtime dependency is required. This documentation does not claim npm publication or that a prepared route is already deployed.
Browser entry exports createGuestClient, mountWidget, SdkError, SDK_VERSION, SCHEMA_HASH and WIDGET_PROTOCOL_VERSION. Server entry @hallify/sdk/server is Node-only and exports createPartnerPreordersClient. Importing the browser module is SSR-safe; guest calls and widget mounting run in the browser. Native wire contracts are generated from the same canonical OpenAPI and explicit Developers registry as the app.
Use exact generated guest methods
The browser client exposes the explicitly registered operations grouped by the literal integration keys storefront, public-preorders, reservations, table-access, guest-payments, guest-observers and guest-portal. Methods use the registry methodName, for example guest.reservations.configuration and guest['guest-payments'].prepareTransition. Careers, Candidate, staff and provider callback APIs are outside this SDK. Each method uses its generated argument/body type and returns { data, status, requestId }; the SDK adds no cache or business-state copy.
createGuestClient accepts apiBaseUrl, fetch and timeoutMs configuration. The default is https://api.hallify.co; an override must pass the same safe public URL policy. Browser Origin/Host/Cookie/Referer and account CSRF are not SDK arguments. Requests omit cookies, use no-store and reject redirects. The browser supplies its actual Origin, including the isolated frame for widget requests.
import { createGuestClient, SdkError } from '@hallify/sdk/browser';
const guest = createGuestClient();
try {
const { data, status, requestId } = await guest.reservations.configuration({
publicHandle: 'example-native-channel',
});
// Render the returned native configuration in the owning guest flow.
} catch (error) {
if (error instanceof SdkError && error.outcome === 'UNKNOWN') {
// Preserve the original command key, payload and private recovery context.
}
throw error;
}Pass only the operation’s canonical credential
Header credentials go in per-call auth keyed by canonical scheme, such as { auth: { reservationManageToken: currentCapability } } or { auth: { guestPaymentAccessToken: paymentCapability } }. Body credentials stay in the generated DTO. There is no extra Authorization argument, global token registry, automatic key issuance or account fallback. Keep private bodies, responses, grants and tickets inside their owning guest flow.
For widget new demand, the frame’s auth may additionally carry storefrontWidgetContext. This signed presentation proof does not replace draft/manage/membership/payment authority. The frame receives it through bootstrap only after checking the exact parent; no swc1 or native capability is sent to the embedding page. Existing continuations keep original native presentation identity and deadlines without inventing fresh proof.
Keep Portal proof, native entry and QR history distinct
guest['guest-portal'] covers bounded history/details, payment receipts, private reentryContext, target proof preparation/verification/status, issueNativeEntry and original QR consent/receipts. History and proof/grant UUIDs are not management bearers. Issue responses preserve the original receipt separately from current.state and nullable current.manageToken; explicit lost-response recovery reuses the original key/input and audience. reentryContext is a private POST command and must stay outside profile/query caches.
Initial association lives under guest['table-access']: portalAssociationStatement, preparePortalBookingProof, preparePortalReentryProof and associatePortalHistory. preparePortalReentryProof requires auth: { tableGuestToken, guestPortalToken } together. Booking preparation and association accept table-only or both credentials. Do not put these credentials or an Origin override into generated args. Actual OTP entry, consent and retry are explicit; wrong codes consume the canonical budget and status is not polled.
Initial entry uses guest.reservations.preparePortalEntry with auth.reservationManageToken, or guest['public-preorders'].preparePortal with the actual READ SESSION in auth.preorderManageToken. Retain the original Idempotency-Key. The result contains only a private reentryContext hint and expiry. Pass that hint and a retained requestId to guest['guest-portal'].requestReentry, then submit the actual delivered code with that same requestId to confirmReentry. Adopt the returned continuation privately; no contact, identity or scope is supplied by the client.
guest['guest-portal'].exchangeAccess accepts an optional exchangeId UUID in the generated body. Save it with the original gpb2 token before sending. Explicit recovery repeats the exact pair after UNKNOWN or reload, and returns only the still-current original result and deadline. Do not create another nonce after an uncertain response or treat omission as recoverable. Expired, revoked or rotated original authority cannot be restored.
import { createGuestClient } from '@hallify/sdk/browser';
const guest = createGuestClient();
// Save the original preparationKey and requestId before calling this function.
// nativeSession is the current legitimate preorder READ SESSION.
export async function requestPortalCode(
nativeSession: string,
preparationKey: string,
requestId: string
) {
const { data: prepared } = await guest['public-preorders'].preparePortal(
{ 'idempotency-key': preparationKey },
{ auth: { preorderManageToken: nativeSession } }
);
return guest['guest-portal'].requestReentry({
guestPortalReentryRequestDto: {
portalHint: prepared.reentryContext.hint,
requestId,
},
});
}
// Call only after the guest submits the actually delivered code.
export function confirmPortalCode(requestId: string, code: string) {
return guest['guest-portal'].confirmReentry({
guestPortalReentryConfirmationDto: { requestId, code },
});
}Keep partner Preorders on the server
The Node entry has exactly partner-preorders.catalog, createQuote, createOrder and getOrder. An authorized administrator issues the actual scoped partner key in /venues/:venueId/settings/fulfillment → resource settings → Integrations, with the active native public channel and service actor. Pass auth.preorderPartnerKey per call; never bundle the key into browser code or substitute a forged browser Origin.
Read the authorized catalog, review the issued quote, retain its exact quoteToken and send createOrder with one saved Idempotency-Key and unchanged payload. These four requests use Bearer partner authentication, not HMAC. The quote token is server-issued and is never signed or reconstructed by the SDK. Outbound preorder webhook verification is a separate protocol, not the simulator callback signing recipe.
For DELIVERY, catalog supplies deliveryMethods, currency and timeZone. createQuote conditionally requires its own original idempotency-key argument; save it before the request and preserve the exact body, including an originally omitted deliveryMethod. Retain the returned deliveryQuoteId with the native quoteToken for createOrder. PREORDER_DELIVERY_QUOTE_UNKNOWN or PREORDER_DELIVERY_QUOTE_NOT_READY is exposed through SdkError.apiCode; explicitly replay the same original request rather than generating a new key or assuming error.details exists. The accepted customer fee stays separate from later staff carrier costs. Follow the Partner preorders guide for configuration and safe tracking fields.
import { createPartnerPreordersClient } from '@hallify/sdk/server';
const key = process.env.HALLIFY_PREORDER_PARTNER_KEY;
if (!key) {
throw new Error('Partner key is required');
}
const partner = createPartnerPreordersClient();
const { data: catalog } = await partner['partner-preorders'].catalog(
{ salesChannelId: '2604de3a-da74-4ad5-89f6-2dfe000d5391' },
{ auth: { preorderPartnerKey: key } },
);Retain the original command after uncertainty
SdkError exposes safe code, status, apiCode, requestId, retryAfter and outcome without raw URLs, bodies or credentials. NOT_SENT, UNKNOWN and NOT_APPLICABLE describe request outcomes, including uncertainty after a sent mutation, separately from native business statuses. A timeout, abort after dispatch, invalid response or network failure can leave a mutation UNKNOWN. The SDK performs no automatic retry and allocates no new idempotency key.
Keep the exact command key, payload and source-bound private recovery journal before submission. Follow native reservation/preorder/table or checkout recovery with that original identity. Re-read current revision and allowed actions on a conflict; preserve original receipts separately from current state. A ready/completed widget event, provider return query or PREPARED receipt does not establish captured funds or final native application.
Respect package and runtime boundaries
The SDK covers the selected Guest PRO and four partner operations, with the same native policy and authority as Hallify. Native public and partner preorder contracts support configured SELF, UBER_DIRECT and WOLT_DRIVE selection, original customer delivery quotes and their safe current tracking projection. Wolt Drive requires real dropoff coordinates. Staff connection settings, dispatch offers, courier dispatch/cancel/readback, local abort and staff histories remain outside the SDK allowlist. The SDK supplies no credential store, staff financial authority or live-provider activation. Browser/device/storage, real DB/HTTP, merchant/provider, deployed artifact and version/package qualification remain separate from source delivery and FAST checks.