Destination Search & Replace
Destination Search & Replace
POST /v1/destination/search and POST /v1/destination/replace — POI discovery for a destination, member-scored.
Two calls curate points of interest (dining and experiences) for a member’s destination:
POST /v1/destination/search— a fresh, two-category candidate list.POST /v1/destination/replace— swap one place out for a new pick, without disturbing the rest of what you’re showing.
Both are session-scoped — require the
X-Session-Id header.
Search
Body (max 64 KiB):
Search takes destinationCity/destinationCountry as flat top-level fields. Replace, and
the plan/extend endpoints, take a nested destination: {city, country, …} object instead. The two shapes are genuinely different — don’t reuse one request
builder for both.
Each place carries an id/name plus provider-merged-or-null fields (category, neighborhood,
priceTier, address, phone, rating, reviewCount, imageUrl, sourceUrl — omitted
individually when the places provider has no data for that field), a code-clamped matchScore
(0–100 integer), and optional model free text in whyForYou.
On a search result, category is omitted whenever the places provider didn’t supply one —
don’t treat it as guaranteed. On a replace result, it always falls back to a generic label
when the provider gives nothing, so it’s always present there.
Replace
Body (max 64 KiB):
replacement (an itinerary-item shape carrying the same provider-merged-or-null fields as a
search result, plus hours when known) and reasoning are omitted together whenever no
replacement could be produced — never a fabricated place.
Business logic
- Search fetches dining and experience candidates independently; if both categories come
back empty, the platform makes no model call and returns the honest-empty shape
(
dining: [],experiences: []) at zero cost. - Replace’s candidate pool is the union of both categories, minus
pinnedPlaceIdsand thedismissedPlaceIditself, fetched fresh on every call (not cached). The model picks exactly one replacement from that offered pool; if it names something outside the pool, the response is the same honest-null shape — not a fabricated place, and not an error.
Places-provider degradation is the current default in the sandbox, not an edge case. If your
environment’s places provider is disabled, /search returns dining: [], experiences: [] and
/replace returns replacement omitted on every call — by design. Don’t read an empty result as
a bug during initial integration; confirm with your partner manager whether live place data is
enabled for your environment.
Errors
Standard envelope. Both: 400 session.unresolved, 401 / 403, 500.
Search additionally: 422 request.validation (blank seatId, destinationCity, or
destinationCountry). Replace additionally: 422 request.validation (blank seatId, blank
destination.city/destination.country, blank dismissedPlaceId, an invalid timeBlockSlot, or
more than 100 pinnedPlaceIds). There is no 429 for either endpoint today — a policy/ceiling
denial surfaces as 500 internal.error.