> ## Documentation Index
> Fetch the complete documentation index at: https://partner.headout.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Products and variants

> How products, variants and their metadata are structured, and what drives the booking form.

## Cities & products

* Products are always fetched at a **city level** — this is the highest aggregation level at Headout
* The following catalog data can be **cached on the partner's side**:
  * Active city list → refresh **monthly**
  * Categories & subcategories → refresh **monthly**
  * Collections → refresh **monthly**
  * Product list & product details → refresh **daily or weekly**
* B2B APIs return a flat list of all products in **no particular order** — there is no ranking, tagging, or B2C grouping (e.g. bestsellers). Any such filtering or ordering must be implemented on the partner's side.
* Instead of waiting for your next scheduled refresh to catch a delisting, use [Event Subscriptions](https://partner.headout.com/docs/api-partner/v2/event-subscriptions/create.md) to get a `product.listing_status_changed` webhook the moment a product is listed or unlisted.

> [!NOTE]
>
> Not all products visible on the Headout B2C surface will appear in the B2B API. If a product is missing from your listing, it could be due to one or more of the following reasons:
>
> * The product is **intentionally hidden or marked non-bookable** for partner traffic
> * The product currently has **no available inventory** (it would also appear unavailable on the B2C website)
> * The product has been **delisted** — check the current B2C website, not older cached data
> * The product's **booking flow is not yet supported** in the Partner API. Currently, only `NORMAL`, `SEATMAP` and `SVG` inventory selection types are supported. Products requiring combo booking or any other non-standard flow are not available via the Partner API

## Ratings, reviews & recommendations

* **Ratings** are exposed via the `reviewsSummary` object on every product returned by `List Products` and `Get Product` — `ratingsCount` (total verified ratings) and `averageRating` (mean on a 1–5 scale).
* **Review text** is **not** exposed via the API. If a one-time dump of review content is genuinely needed for a launch (e.g. seeding a partner-side display), this can be shared on request via your Headout SPOC.
* **Recommendations and similar-products APIs are not provided.** Partners that want related-product surfaces should derive them from the catalog on their own side (e.g. by collection / category / subcategory grouping).

## Inventory selection types

> [!NOTE]
>
> This subsection is relevant to **API Partner accounts** (booking flow). Affiliate accounts do not book through the API.

Every product carries an `inventorySelectionType` that tells you how date / time / seat selection is presented and which inventory endpoint to call. There are three values today; all are supported for booking.

| `inventorySelectionType` | What it means | Inventory + booking flow |
| - | - | - |
| `NORMAL` | Standard date and time slot selection. Most products. | [`List Inventory`](https://partner.headout.com/docs/api-partner/v2/inventory/list-by-tour) → [`Get Inventory Details by ID`](https://partner.headout.com/docs/api-partner/v2/inventory/details) → [`Create Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/create) → [`Update Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/update) |
| `SEATMAP` | Seat-level selection (theatre, live entertainment). | [`Seatmap availabilities`](https://partner.headout.com/docs/api-partner/v2/seatmap/availabilities-by-variant) → [`List Inventory - Seatmap`](https://partner.headout.com/docs/api-partner/v2/seatmap/inventory) → [`Validate`](https://partner.headout.com/docs/api-partner/v2/seatmap/validate) → [`Create Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/create) → [`Update Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/update) |
| `SVG` | Section-level selection on a venue map. The customer picks a section and seats are assigned automatically. | [`List availabilities - Normal`](https://partner.headout.com/docs/api-partner/v2/availabilities/normal-availabilities) → [`Venue Map`](https://partner.headout.com/docs/api-partner/v2/seatmap/svg) → [`List Inventory`](https://partner.headout.com/docs/api-partner/v2/inventory/list-by-tour) → [`Create Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/create) → [`Update Booking`](https://partner.headout.com/docs/api-partner/v2/bookings/update) |

Read `inventorySelectionType` from each product and branch your flow accordingly — never assume one type for all products. If a future value appears that isn't in this list, treat it as unsupported for booking and fall back to displaying the product as not bookable until guidance is updated.

## Search

The Headout Partner API does **not** expose a free-text or real-time search endpoint. Catalog discovery is structured, not query-based:

* Start with `List Cities` to scope the catalog.
* Narrow by `Collections`, `Categories`, or `Subcategories`.
* Use `List Products` with the relevant filters to retrieve products.

If you need free-text search in your own surface, index the Products listing on your side and run search against your local index.

## Variants

A single product can have multiple variants. Variants can differ by **many parameters**, including but not limited to:

* Inclusions and exclusions
* Cancellation or reschedule eligibility
* Meeting point or pickup details
* Ticket type and fulfillment behavior
* Pricing and availability patterns

Variants must be treated as **independent purchasable units**, not as metadata.

**Example:** The Eiffel Tower is a single *product*. Its *variants* could be:

* Eiffel Tower – 2nd Floor Access
* Eiffel Tower – Summit Access
* Eiffel Tower – English Guided Tour
* Eiffel Tower – Spanish Guided Tour

Each of these is a separate bookable unit with its own pricing, availability, and policies.

## Variant metadata: `properties` and `propertiesV2`

Variants return a `properties` map that carries **additional identifying information about that variant**. This is not decorative metadata — it is a critical field. \
\
Treat them as dynamic key-value data, not fixed schema fields.

* `properties` is a plain object whose values are strings
* `propertiesV2` can usually be ignored

For example, one variant might carry a language-based property:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "properties": {
    "LANGUAGE_CODE": "EN"
  },
  "propertiesV2": {}
}
```

Another variant might be tied to nationality or a product-specific classification:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "properties": {
    "NATIONALITY": "MALAYSIAN_CITIZEN"
  },
  "propertiesV2": {}
}
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "properties": {
    "NUMBER_OF_ATTRACTIONS": "3_ATTRACTIONS"
  },
  "propertiesV2": {}
}
```

⚠️ `properties `**is critical and must never be skipped.**

If a variant carries any `properties`, they **must be displayed prominently alongside the variant name** — not buried in fine print or omitted.

Two variants can have different prices solely because their `properties` differ — by language, nationality, attraction count, or another variant-level condition. This information directly determines which variant the customer should select. **If you don't show it, customers can book the wrong variant and face issues at the venue,** increasing the support load and customer dissatisfaction.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.