Skip to content
KismetKismetDevelopers
llms.txt

The canonical stay URL

View .md

Every Kismet site carries the stay a guest is shopping for in the URL under ONE set of key names, so a search bar, a results page, and a property page agree with each other across reloads, shared links, and the move to a property page. The stay-query contract makes this a MUST: keys come from the StayUrlParam enum (or a registered site param), and reads and writes go through the SDK helpers only.

StayUrlParam is the single enum. Never spell these keys as string literals — compare the enum member, or derive the key lists from it.

Key Meaning Default Written
checkIn, checkOut ISO days; both or neither, checkOut > checkIn omitted data
guests integer 1–16 2 (omitted) data
beds, sleeps minimums; 0 means any 0 (omitted) data
minPrice, maxPrice whole currency units omitted data
currency ISO-4217-style code; only with a price bound USD data
sort recommended · price-asc · price-desc · name-asc · bedrooms · sleeps recommended data
pets, type, group, tags, prioritize optional filters omitted data
sheet slug of the open quick view omitted UI-only
layout grid · map grid UI-only

Two write modes, one shared list: data keys change results, so useStayQuery writes them with router.replace({ scroll: false }). UI-only keys (sheet, layout) are written shallow with history.replaceState and never trigger a server re-read of results. STAY_DATA_PARAM_KEYS, STAY_UI_PARAM_KEYS, and ALL_STAY_PARAM_KEYS all derive from the enum.

import { parseStayQuery, stayQueryToSearchParams } from '@kismet-tech/sdk';
const stayQuery = parseStayQuery(searchParams); // invalid values fall back silently
const href = `/properties?${stayQueryToSearchParams(stayQuery).toString()}`;

A param at its default is omitted; garbage is dropped, never thrown. Use countStayNights(stayQuery) and describeActiveStaySettings(stayQuery) for nights and the active-settings line.

const [stayQuery, updateStayQuery] = useStayQuery({ router, isKnownSheetSlug });
updateStayQuery({ checkIn: '2026-10-12', checkOut: '2026-10-15' }); // router.replace, scroll: false
updateStayQuery({ sheet: 'fern-ridge-cabin' }); // shallow write, no re-read
updateStayQuery({ sheet: undefined }); // close: removed

Sheet rules: written shallow, removed on close, read after hydration, an unknown slug resolves to closed (isKnownSheetSlug), and preserved when data keys change. A Next App Router adapter — createNextStayQueryController from @kismet-tech/sdk/next — takes useRouter() / usePathname() / useSearchParams() outputs as-is and follows the same two write modes.

A site-specific param must be namespaced x-<site>-<name> and registered; anything else is an invented key. Registration goes into the same registry the parser, serializer, build gate, and kismet check read. Unprefixed keys and built-in collisions are refused.

export const acmeView = defineStayParam({
key: 'x-acme-view',
mode: 'ui',
parse: (raw) => (raw === 'list' || raw === 'grid' ? raw : undefined),
default: 'grid',
});

Two gates back the contract’s MUSTs and MUST NOTs:

  • content/stay-params (runtime, npx kismet check) — fails on any rendered link carrying an invented stay key (?minBedrooms=2, ?check_in=…, ?price_min=…).
  • recipes/stay-query-source (static, npx kismet recipes check --app-dir ., the starters’ check:recipes) — fails when a file that declares the stay-query contract touches searchParams / URLSearchParams / router.push|replace outside the SDK helpers, or uses a non-canonical, unregistered key.

Where to go next: What is a contract for the requirement levels, and Recipes and implementation tests for declaring implementations.