Skip to content
KismetKismetDevelopers
llms.txt

Staging catalog previews

View .md

Build 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.

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.

  1. Create an active TEST installation and credential with collection-wide vacation_rentals.read. A LIVE credential cannot request view=staging. No additional pricing or booking capability is needed for this content preview.
  2. 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.
  3. 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.

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.

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.

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.

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.

Terminal window
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"

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.

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.

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.