# Build natural-language search

> Return ranked stays, card details, indicative prices, and optional guest-journey capture through one search operation.


Let visitors describe the stay they want, then render Kismet's ranked results with your own cards. Search returns property details, the serving collection, relevance evidence, and indicative prices when available. It does not create a quote or authorize a booking.

## Set up access

Create a collection-scoped installation with `search.read` using [Create an application and key](https://developers.kismet.travel/guides/developer-access.md). A browser can use an origin-bound publishable key. A backend can use a restricted server key. TEST and LIVE are separate installations; use TEST for rehearsals.

## Search with the SDK

```ts
import { createKismetClient } from '@kismet-tech/sdk';

const kismet = createKismetClient({
  apiKey: publishableKey,
  collection: 'coastal-stays',
  baseUrl: 'https://api.ksmt.app/v1',
});

const result = await kismet.bookableProduct.search({
  query: 'quiet beach home with a pool',
  checkIn: '2027-01-11',
  checkOut: '2027-01-16',
  guests: 4,
  topK: 6,
});

for (const hit of result.ranked) {
  console.log(hit.product.name, hit.product.servingUrl, hit.price?.stay);
}
```

Send both dates or neither. Explicit dates and guest count take precedence over facts inferred from the query. The [operation reference](https://developers.kismet.travel/api/reference/search-bookable-products.md) describes validation and limits.

Equivalent server-side REST request:

```bash
curl https://api.ksmt.app/v1/developer/collections/coastal-stays/search \
  -H "Authorization: Bearer $KISMET_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"query":"quiet beach home with a pool","checkIn":"2027-01-11","checkOut":"2027-01-16","guests":4,"topK":6}'
```

## Render truthful cards

- Preserve `ranked` order and returned relaxation flags; a relevance score is not availability.
- Use `product.bathrooms`, `location`, and `homeCollection` when present. Do not infer collection membership from names or URLs.
- `price.stay.totalBeforeTaxMinor` includes required fees but excludes taxes. `nightlyMinor` is the corresponding nightly display amount. Amounts are integer minor units with a currency; do not compare different currencies.
- `price.nightlyFrom` is an undated indicative amount with its own horizon. Do not substitute it for a missing dated stay price.
- Null or absent prices mean no price to display, not zero or sold out. Recheck availability and current pricing through the supported checkout path.
- Older API responses may omit newer card or capture fields. The SDK preserves those omissions rather than inventing defaults.

## Optionally record the search on a guest journey

Pass the existing canonical `kid_` session as `guestSessionId` when available. Do not generate a session just to make capture succeed. A same-origin backend handling a signed-in guest can instead pass its server-held guest access token as `guestAccessToken`; the SDK sends it in `X-Kismet-Guest-Token`, not in JSON or a URL. A guest token takes precedence over a supplied session ID.

Search still returns discovery results when no journey can be recorded. Inspect `capture` separately:

| Result | Meaning |
| --- | --- |
| `recorded: true`, `reason: null` | The ask was recorded on the guest journey. |
| `no_guest_session` | No guest session was supplied. |
| `invalid_guest_session` | The supplied guest identity could not be verified. |
| `no_active_journey` | There is no eligible active journey for this session. |
| `environment_mismatch` | TEST capture would attach to live guest activity and was refused. |
| `capture_failed` | Capture failed; discovery results remain usable. |

TEST asks are sandbox activity and appear only in Developer mode. Capture does not grant marketing consent, enroll a member, or imply a booking. It is also separate from the [event ledger and webhook destinations](https://developers.kismet.travel/guides/developer-events.md): do not assume every recorded search emits an external webhook.

## Verify your integration

Test an undated query, a complete date pair, unknown pricing, an empty result, and a response with relaxed matching. Verify request dates/guests, ranking, currency, and fee/tax labels. For capture, check the response and the correct TEST or LIVE journey; a successful HTTP response alone does not prove capture or semantic ranking.
