---
title: "Explore Place Details Batch"
method: GET
path: "/explore/places"
tags: ["explore"]
---

# Explore Place Details Batch

`GET /explore/places`

Batched detail payloads — one round trip for a whole slate (the
client's depth-2 prefetch transport, docs/EXPLORE_SERVING_SHAPE.md §6).
Comma-separated ids, capped; unknown ids skipped; order preserved.
Spine caches only; logs nothing. `revalidate=true` marks the client's
hydration-pending poll loop: same payload, but the exposure-lazy
hydration trigger is skipped so polling can't extend its own pending
signal (docs/HYDRATION_PROPAGATION_SPEC.md §4.2).

## Query parameters

- `ids` string, required
- `revalidate` boolean

## Response `200`

Successful Response

- ExplorePlaceDetails[]
  - `place_id` string, required
  - `name` string, required
  - `category` string, nullable, required
  - `city` string, nullable, required
  - `country_code` string, nullable, required
  - `lat` number, nullable, required
  - `lng` number, nullable, required
  - `photos` string[], required
  - `photo_thumbhashes` string[]
  - `rating` number, nullable, required
  - `num_reviews` integer, nullable, required
  - `description` string, nullable, required
  - `address` string, nullable, required
  - `neighborhood` string, nullable
  - `hours` PlaceHours — Hours representation (primarily from Google Places).
    - `open_now` boolean, nullable
    - `weekday_descriptions` string[]
  - `web_url` string, nullable
  - `michelin_award` string, nullable
  - `michelin` MichelinDistinction — A place's Michelin Guide distinction, structured. Canonical rationale — the TS mirror and the renderers point here rather than restating it. Rides alongside `michelin_award` rather than replacing it: that field is a pre-rendered label ("★★★"), and a label cannot drive iconography. An award string we don't recognise yields NO distinction (we never paint a mark we can't justify) while still surfacing verbatim in `michelin_award`, so a new tier degrades to text rather than disappearing.
    - `tier` 'stars' | 'bib_gourmand' | 'selected', required
    - `stars` integer, nullable
    - `green_star` boolean
    - `url` string, nullable
    - `cuisine` string, nullable
  - `kind` 'place' | 'stay'
  - `stay` StayFacets — What a Michelin Guide hotel carries that an ordinary place doesn't. Same rationale as `MichelinDistinction`, one category later: `key_label` is the Guide's own pre-rendered string ("Two MICHELIN Keys"), and a label cannot drive iconography, so `tier`/`keys` ride beside it. A tier we don't recognise yields no structured distinction while still surfacing verbatim in `key_label` — a new tier degrades to text rather than disappearing. A sub-object rather than flat columns on `ExploreItem`: otherwise every future category (a tour, a tasting menu) adds its own nullable fields to the type EVERY card in the app carries.
    - `key_label` string, nullable
    - `tier` 'keys' | 'selected', nullable
    - `keys` integer, nullable
    - `guide_url` string, nullable
    - `editorial` string, nullable
    - `check_in` string, date, nullable
    - `check_out` string, date, nullable
  - `hydration_pending` boolean

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/stardrift/apis/fastapi.md) · [All operations](https://skmtc.dev/stardrift/apis/fastapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/stardrift/fastapi/revisions/00746572572a/schema)
