The canonical stay URL
View .mdEvery 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.
The canonical keys
Section titled “The canonical keys”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.
Read and write through the helpers
Section titled “Read and write through the helpers”import { parseStayQuery, stayQueryToSearchParams } from '@kismet-tech/sdk';
const stayQuery = parseStayQuery(searchParams); // invalid values fall back silentlyconst 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.
The one hook (React and Next)
Section titled “The one hook (React and Next)”const [stayQuery, updateStayQuery] = useStayQuery({ router, isKnownSheetSlug });
updateStayQuery({ checkIn: '2026-10-12', checkOut: '2026-10-15' }); // router.replace, scroll: falseupdateStayQuery({ sheet: 'fern-ridge-cabin' }); // shallow write, no re-readupdateStayQuery({ sheet: undefined }); // close: removedSheet 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.
Site-specific params (L4)
Section titled “Site-specific params (L4)”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',});Compliance is required, not advised
Section titled “Compliance is required, not advised”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 thestay-querycontract touchessearchParams/URLSearchParams/router.push|replaceoutside 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.