Staging catalog previews
View .mdBuild a staging directory, browse a group’s rooms, and open a room-preview drawer using the same catalog methods your production site uses. Published content remains the default. A TEST key alone does not expose unpublished content.
This guide describes the source-pinned SDK candidate and its matching API extension.
Confirm that your API deployment supports view=staging on all four reads below.
Installing the candidate does not enable preview access by itself. See
SDK evaluation for installation.
What you can build
Section titled “What you can build”| UI task | REST operation | SDK method on client |
|---|---|---|
| Directory or group selector | GET groups | bookableProductGroup.list() |
| Group heading and content | GET group | bookableProductGroup.get() |
| Room grid in a group | GET rentals | vacationRental.list() |
| Room gallery and details | GET rental | vacationRental.get() |
These are optional views on existing operations, not a separate preview API.
The same flow works for a building directory or another approved curated group.
Use semanticType: 'BUILDING' only when your UI needs buildings; omit it for
all eligible classifications. Classification is separate from STANDARD/DROP
grouping behavior. Catalog classification.
A room-preview drawer displays content, not checkout. You own that presentation. Use the supported Kismet Fixtures integration for trusted guest or checkout experiences; this read extension does not install or activate them.
Set up access
Section titled “Set up access”- Create an active TEST installation and credential
with collection-wide
vacation_rentals.read. A LIVE credential cannot requestview=staging. No additional pricing or booking capability is needed for this content preview. - Ask a collection manager to approve the specific groups and source inventory for preview. These are two independent, expiring approvals, not capabilities you can add by changing a URL or enabling Developer mode.
- Keep the preview site out of search indexes and shared caches. Preview approval permits shareable storefront content; it is not a confidentiality boundary. If the site needs restricted access, protect it separately.
Manager approval through MCP
Section titled “Manager approval through MCP”Sign in with Kismet and use get_fixture_status to inspect the current draft
rules and staging.inventory_preview. An authorized manager can use
set_fixture_rules with staging_group_slugs and
staging_inventory_collections to approve the intended scope for seven days.
The tool requires Fixture-management permission on the destination collection and
manage access to each source collection. A DEVELOPER role alone does not grant
Fixture writes. See MCP authentication and access.
Preserve the complete existing draft rule set. set_fixture_rules replaces
rules; do not pass an empty array unless clearing those rules is intended.
First preview the request without confirm, review its scope and diff, then
repeat with confirm: true. Omitting an approval field preserves it; passing
[] revokes that approval. Renewing group approval does not renew source-inventory
approval. No production Fixture publish is needed to approve a preview.
Only same-collection STANDARD groups qualify, excluding guest-save and DROP groups. An unpublished room must belong to an approved group and have active membership in the installation collection, plus active, directory-visible membership in an approved public, active, non-draft source collection. The room must remain active, non-deleted, and have an unpublished content object.
Cross-collection links may remain hidden from the installation’s public directory: the two explicit staging approvals authorize their preview without changing that visibility flag. Published rooms still require ordinary directory visibility. Approval does not create groups, change membership, or publish content.
Read with the SDK
Section titled “Read with the SDK”Run this in a server-only module using a source-pinned SDK build that includes
CatalogReadOptions. Keep the server credential in server environment variables,
never in a NEXT_PUBLIC_ variable.
import { createKismetClient } from '@kismet-tech/sdk/server';
const client = createKismetClient({ apiKey: process.env.KISMET_DEVELOPER_API_KEY!, baseUrl: process.env.KISMET_API_BASE_URL ?? 'https://api.ksmt.app/v1', // Prevent framework fetch caches from retaining expiring preview content. fetchImpl: (input, init) => fetch(input, { ...init, cache: 'no-store' }),});const view = 'staging' as const;
const groups = await client.bookableProductGroup.list({ view, semanticType: 'BUILDING', limit: 50,});
// Example selection. In your UI, use the group chosen by the visitor.const selectedGroup = groups.data[0];if (selectedGroup) { const group = await client.bookableProductGroup.get(selectedGroup.id, { view }); const rooms = await client.vacationRental.list({ view, group: group.slug, minGuests: 2, limit: 50, });
// An empty list is a valid result. Do not request an undefined room ID. const selectedRoom = rooms.data[0]; if (selectedRoom) { const room = await client.vacationRental.get(selectedRoom.id, { view }); // Render room.media.gallery and the detail fields in your preview drawer. // A list row is a summary with a hero, not a substitute for this detail read. }}If you use a publishable key directly in a browser, its exact origin must be authorized on the TEST installation. Browser origin restrictions do not make preview content confidential.
Pagination and filters
Section titled “Pagination and filters”Keep view and every filter when following page.nextCursor. Group listing
also supports semanticType; room listing supports group, minBedrooms,
minBathrooms, minGuests, and petsAllowed. These select catalog content
and capacity, not dated availability.
const roomQuery = { view, group: 'example-building', minGuests: 2, limit: 50 };const firstPage = await client.vacationRental.list(roomQuery);if (firstPage.page.nextCursor) { const nextPage = await client.vacationRental.list({ ...roomQuery, cursor: firstPage.page.nextCursor, });}Use a returned group slug instead of the example value. If the selection changes,
start again without a cursor. Eligibility and filters are checked before paging.
Group links.self and links.bookableProducts preserve staging view;
memberCount counts eligible members, not available rooms for particular dates.
Read with REST
Section titled “Read with REST”Set KISMET_API_BASE_URL=https://api.ksmt.app/v1 and a TEST server key in
KISMET_DEVELOPER_API_KEY. The key already carries its collection: read the
collection slug from GET /developer/credential and export it as
COLLECTION_SLUG for the examples below.
Use returned identifiers for GROUP_ID, GROUP_SLUG, and ROOM_ID.
These examples run on your server or in a local terminal, not in browser code.
curl --get "$KISMET_API_BASE_URL/developer/credential" \ --header "Authorization: Bearer $KISMET_DEVELOPER_API_KEY"# Copy the collection "slug" from the response:export COLLECTION_SLUG=your-collection-slug
curl --get "$KISMET_API_BASE_URL/developer/collections/$COLLECTION_SLUG/bookable-product-groups" \ --header "Authorization: Bearer $KISMET_DEVELOPER_API_KEY" \ --data-urlencode "view=staging" --data-urlencode "semanticType=BUILDING"
curl --get "$KISMET_API_BASE_URL/developer/bookable-product-groups/$GROUP_ID" \ --header "Authorization: Bearer $KISMET_DEVELOPER_API_KEY" \ --data-urlencode "view=staging"
curl --get "$KISMET_API_BASE_URL/developer/collections/$COLLECTION_SLUG/vacation-rentals" \ --header "Authorization: Bearer $KISMET_DEVELOPER_API_KEY" \ --data-urlencode "view=staging" --data-urlencode "group=$GROUP_SLUG" \ --data-urlencode "minGuests=2"
curl --get "$KISMET_API_BASE_URL/developer/vacation-rentals/$ROOM_ID" \ --header "Authorization: Bearer $KISMET_DEVELOPER_API_KEY" \ --data-urlencode "view=staging"Interpret publication and expiry
Section titled “Interpret publication and expiry”A staging view includes eligible published content as well as approved unpublished
content. Do not mark every result as unpublished merely because you requested
view=staging. A staging-only room has publication metadata like this:
{ "publishedAt": null, "updatedAt": "2026-09-24T00:00:00.000Z", "visibility": "staging", "stagingExpiresAt": "2026-09-30T00:00:00.000Z"}stagingExpiresAt is the earlier of the group and source-inventory approvals.
A staging-only group’s expiry describes its group approval, so the group can
remain visible after permission to preview its unpublished rooms expires.
Ordinary published responses retain their existing shape; absence of staging
metadata is not a missing publication date.
Show a preview label for staging-only content. API responses use
Cache-Control: private, no-store; propagate that policy through your BFF.
Do not statically export or put preview HTML in ISR/shared caches. Set noindex on
your own preview pages. Remove expired preview content from the UI and refetch;
a timestamp does not override earlier revocation.
Empty results and errors
Section titled “Empty results and errors”The SDK raises KismetApiError with status, code, and requestId.
Do not silently substitute local fixture data or retry a denied request with
broader access.
| Result | Meaning and UI response |
|---|---|
| Empty group or room list | No eligible content matches the current scope and filters. Show an empty preview state, not “sold out.” |
403 CAPABILITY_NOT_GRANTED |
Check the TEST installation and required capability. Developer mode does not convert a LIVE key. |
403 RESOURCE_NOT_GRANTED |
The detail is not accessible, including after preview revocation. Remove it and reload the selection. |
403 ORIGIN_NOT_ALLOWED |
The browser origin is not authorized for the publishable key. Check the exact scheme, host, and port. |
400 INVALID_GROUP |
The selected group is not accessible in this collection/view. Refresh the group selector. |
400 INVALID_CURSOR |
The cursor no longer belongs to the eligible filtered set. Restart from the first page with the same intended view and filters. |
401 |
Check credential validity and expiry; do not fall back to anonymous access. |
Missing or expired preview approvals restore published-only eligibility. Revoking the inventory approval can remove unpublished rooms while leaving the separately approved group visible. It does not remove genuinely published content.
Pricing, checkout, and promotion
Section titled “Pricing, checkout, and promotion”This extension does not add rates, dated availability, unpublished-room review,
policy or calendar subresource reads, quotes, booking writes, or public publication.
Staging-only rooms do not receive pricing.nightlyFrom, even with rates.read.
Published rooms retain their existing grant-controlled behavior.
Keep “Book” actions unavailable for a content-only preview. Do not turn a missing price into zero or describe a capacity filter as an availability check. Group pricing and managed checkout have separate contracts and eligibility.
Before promotion, publish the intended catalog through the normal approval process, switch to the default published view, and verify the same directory, room list, and detail flow with the appropriate LIVE installation. Verify pricing and checkout separately. Never carry a preview allowlist or a TEST credential into production.