Skip to content
Sections

Guides

Guest observer baseline and ticket

Read a native snapshot and real cursor, then request a separate ticket. Native WebSocket qualification is pending.

Start with an owned native resource

Baseline and ticket issuance accept PREORDER, RESERVATION, WAITLIST and TABLE_SESSION. Obtain the exact native UUID and current READ capability from its owning flow first. PREORDER addresses accepted ASAP or scheduled fulfillment. QR requires claimed membership and its actual session. Public handles, drafts, join tokens and account sessions do not provide this READ authority.

The canonical source provides the HTTP baseline, separate ticket issuance and public-guest protocol described here. Native WebSocket qualification is still pending. The example prepares admission data and a session frame; it does not open a WebSocket or demonstrate a live event.

Read a baseline, then request one ticket

POST kind, resourceId and the current private capability directly to the baseline command. The server checks the actual browser Origin, captures a real journal barrier, then rechecks native authority before reading the safe current snapshot. Browser code uses credentials: 'omit' and lets the browser supply Origin. Account cookies, Authorization headers and device credentials provide no fallback.

The input values below are synthetic. Both HTTP replies must come from your actual authorized server: the code never invents a cursor, snapshot, ticket or scopeBinding. It keeps responses in local memory, sends no request from this documentation page, and prepares only a protocol frame while native WebSocket qualification remains pending.

  1. Obtain one of the four supported native resource UUIDs and its current READ capability within the approved presentation Origin.
  2. Read the baseline first. Retain its snapshot, public-guest streamId, exact returned cursor and scopeBinding together; use snapshot.kind to select its generated response schema.
  3. Issue a separate ticket for the same resource and capability. A baseline does not issue a ticket or replacement native capability.
  4. Require the ticket's scopeBinding to equal the baseline's. If authority changed, stop and obtain a fresh baseline rather than combining replies.
  5. Prepare the session frame with that same public-guest cursor and a scopeKey made from the matching binding, ':' and a client context of 1–128 characters. Offer the ticket separately alongside hallify.socket.v1 at the source protocol's public upgrade.
  6. Keep the snapshot, cursor and private ticket in the owning flow's memory. Complete native WebSocket qualification before treating this source protocol as a verified live journey.
Request examples
const resource = {
  kind: 'PREORDER',
  resourceId: '00000000-0000-4000-8000-000000000001',
  capability: 'synthetic-read-capability-for-example-only',
};
const requestOptions = {
  method: 'POST',
  credentials: 'omit',
  cache: 'no-store',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(resource),
} satisfies RequestInit;

const baselineResponse = await fetch(
  'https://api.hallify.co/public/guest-observers/baseline',
  requestOptions
);

if (!baselineResponse.ok) {
  throw new Error(`HTTP ${baselineResponse.status}`);
}

const baseline = await baselineResponse.json();
const validBaseline =
  baseline.streamId === 'public-guest' &&
  typeof baseline.cursor === 'string' &&
  baseline.cursor.length > 0 &&
  typeof baseline.scopeBinding === 'string' &&
  baseline.scopeBinding.length > 0 &&
  baseline.snapshot?.kind === resource.kind;

if (!validBaseline) {
  throw new Error('A current native observer baseline is required.');
}

const snapshot = baseline.snapshot;

const ticketResponse = await fetch(
  'https://api.hallify.co/public/guest-observers/tickets',
  requestOptions
);

if (!ticketResponse.ok) {
  throw new Error(`HTTP ${ticketResponse.status}`);
}

const ticket = await ticketResponse.json();

if (ticket.scopeBinding !== baseline.scopeBinding) {
  throw new Error('Observer authority changed; request a fresh baseline.');
}

const clientContext = 'example-panel';
const upgradeProtocols = ['hallify.socket.v1', ticket.ticket];
const sessionFrame = {
  v: 1,
  kind: 'session',
  scopeKey: `${baseline.scopeBinding}:${clientContext}`,
  streams: [baseline.streamId],
  cursors: { [baseline.streamId]: baseline.cursor },
};

Respect admission and native authority

The baseline contains a safe current snapshot, not a replacement business capability. PREORDER exposes authorized fulfillment status and schedule, RESERVATION booking status and party/schedule fields, WAITLIST status and an optional claim window, and TABLE_SESSION the authorized membership, slot labels and access epochs. Native domain reads remain authoritative for other business details.

The source upgrade path is /socket/public. Offer exactly hallify.socket.v1 and the separate private gpot1_ ticket; the server selects only the stable protocol. After ready, the session frame subscribes only to public-guest and carries the unchanged baseline cursor under that same stream key. The cursor and scopeBinding identify resource and authority context; neither grants access by itself. No live-event example or WebSocket execution is included here.

The database sets ticket expiresAt to at most thirty seconds and no later than current native or presentation deadlines. This limits one-use admission, not the live lease. A consumed or expired ticket cannot authorize another connection. Do not queue or prefetch tickets; at most six can remain pending for one native grant, and 429 requires observing Retry-After.

If the baseline returns 503, stop without a substitute cursor. On resyncRequired or changed resource authority, obtain a fresh baseline; a new upgrade requires a separate matching ticket. Do not reuse a cursor across resources or grants. Revoked, rotated, retired, replay-only and unclassified sources cannot restore authority through an old snapshot. A ticket never grants a booking, order, staff decision or payment command.

Keep credentials inside the guest flow

Keep native capabilities and tickets outside URLs, cookies, Redux, logs, analytics and error payloads. Confine private snapshots and cursors to the owning resource context. Both HTTP replies use Cache-Control: no-store. Keep a cursor with its exact resource, snapshot and scopeBinding; do not decode, synthesize or repair it. Initial presentation selection uses x-hallify-connection-id only on operations that declare it; observer commands use the authority already captured by the native grant.

JOIN is not an observer resource. The SDK exposes HTTP baseline/ticket methods without inventing an automatic WebSocket client or polling loop. Widgets use the same retained native READ authority; observer traffic grants no financial authority. Native WebSocket, browser/live and production qualification remain separate from HTTP helpers and source delivery.

Hallify uses essential cookies and optional analytics.

Essential cookies keep sign-in, locale, and theme preferences working. Analytics is off until you choose to allow it.