Agent Search
Dense agent search revealing platform, deeplinks, per-week availability, options, and commission preview
/agent/boatsThe dense "one boat per line" agent feed. It reuses the same matching and value-ordering as the consumer search, then re-fetches each match with agent-only columns and enriches it for the requested week.
Authentication
Logged-in session as an active agent. Returns 401 when not logged in, 403 when the session has no active agent profile. See the Agent API overview.
Query Parameters
Accepts the same parameters as the consumer search (GET /api/boats). All are optional; with none, it returns the value-ranked default set.
| Parameter | Type | Description |
|---|---|---|
location_id | integer | Location to search (marina/city/region resolved server-side). |
location_type + location_value | string | Alternative to location_id — e.g. location_type=text&location_value=Lefkada. Named sailing regions (Dalmatia, the Dodecanese) resolve too. A value that matches no known place returns an empty result set rather than boats from elsewhere. |
country_code | string | Narrows a location_type of state, city or municipality to one country (e.g. GR). Ignored for country, text and location_id. |
type | string | Boat type(s), comma-separated: sailboat, catamaran, yacht, motorboat, gulet, rib. |
d | string | Charter dates as YYYY-MM-DD,YYYY-MM-DD (Saturday→Saturday). A range spanning several charter weeks is priced as all of them — a fortnight is week 1 + week 2. A single date does not reliably availability-filter — always pass a range. |
guests | integer | Minimum capacity — only boats with capacity ≥ guests match. Also folds per-person required extras into the quoted price. |
priceMin / priceMax | number | Daily-rate bounds (EUR). |
cabins / berths / toilets | integer | Minimum counts. |
lengthMin / lengthMax | number | Length bounds (feet). |
yearMin / yearMax | integer | Build-year bounds. |
rentalTypes | string | Comma-separated: bareboat, skippered, no_licence_needed. no_licence_needed means the operator asks no licence of the charterer — it does not mean a skipper comes with the boat. |
features | string | Comma-separated equipment slugs. |
manufacturerSlug | string | Manufacturer filter. |
makes | string | Comma-separated make/model filter: bali (whole make) or bali:4.2 (one model). Same semantics as GET /api/boats. Use this — not q — to search by model. |
q | string | Boat NAME filter — matched against the boat's title only, never its model. For a make or model, use makes. |
sort or sortBy | string | recommended (default, best value first), price-low, price-high, rating (aliases price_asc / price_desc accepted). |
limit | integer | Results to return. Default 20, max 50. |
offset | integer | Number of results to skip. |
Request
Response
When no d week is passed, price.unit is "day" (amount is the daily rate), price.weeks/price.nights are null, week.index is -1, and week.available is null.
The response carries no pagination cursor (hasMore / next_offset): page with offset + limit against total.
Response Fields
| Field | Type | Description |
|---|---|---|
boats[].id | string | Boat UUID |
boats[].slug | string|null | URL slug |
boats[].title | string | Boat name (falls back to model when the boat has no valid name) |
boats[].model | string|null | Model name |
boats[].brand | string|null | Manufacturer name |
boats[].manufacturer | object|null | { id, name, slug, logo_url } |
boats[].boat_type | string | Type of boat |
boats[].year / capacity / cabins / berths / heads / length_ft | number|null | Specs. length_ft is length overall (LOA). |
boats[].average_rating / review_count | number|null | Guest review summary |
boats[].location | object | { id, name, city, country, country_code } |
boats[].currency | string | Currency code (operator's base currency, default EUR) |
boats[].hero_image_url | string|null | The boat's hero image, 1200×800 variant on media.charter.boats |
boats[].images | string[] | Up to 5 gallery images, ordered with the same category-diverse logic as the boat detail hero. Served as the 1200×800 WebP variant on media.charter.boats — hotlink these directly; the un-resized original is not a public URL. |
boats[].series | object[] | Forward price/availability series for the graph: one entry per week from the current week, up to 26 weeks (fewer near the end of the 52-week window). { w, start, price, avail, option, booked } — w week index, start that week's start date on this boat's own changeover day, price the per-day price for that week (0 = not sold that week, never free), avail free in the availability calendar, option / booked whether a hold or a booking covers it. |
boats[].features | object[] | Equipment & amenities: { label, slug } — label is the display spelling matching the detail page, slug the canonical filterable feature (or null for non-canonical items) |
boats[].deposit | number|null | Security deposit (null when none is set) |
boats[].platform | string | Agent-only. Source pricing platform: mmk, nausys, or direct. Marks the price-of-record deeplink. |
boats[].rank | number|null | Value rank used by recommended ordering (lower = better value; null when the boat has no bookable priced week) |
boats[].price | object | Headline price: amount + unit (week when a date is set, else day), weeks/nights (the span amount covers — a fortnight search returns weeks: 2, nights: 14, and amount is both weeks at their own rates), discount_pct, required_extras, rental (bareboat / skippered / skipper optional / skipper required (paid extra)), payment_terms. When the boat cannot be sold in the requested week — it has no price for it, or it is already booked in it — the price comes from the nearest week it can be sold in among the weeks it was matched on (for a similar backfill boat that includes ±1 week), and week_start carries that week's start on this boat's own changeover day, which is not always a Saturday. week_start is null when the price is for the week you asked for — and also when the boat has no sellable week in range, in which case the quote stays on the requested week and amount can be 0 (nothing to sell). required_extras is a charter-length total (per-person parts only once guests is set); with no date it is the boat's cheapest priced week, not 0 — a mandatory fee belongs to the boat, not to the dates. required_extras_unit says which span it covers (stay with dates, week without, where amount is per day), and required_extras_from is true when the figure is a floor — no priced week charges less and one charges more. |
boats[].week | object | Selected-week detail: index (the requested week in the rolling 52-week window), available (whether that requested week is free), and price_per_day, discount_pct, charter_total, required_extras, required_extras_from, all_in — these price figures come from the same quoted week as price (see week_start). index=-1 / available=null when no week is set. |
boats[].commission_preview | object | Agent-only. { estimate, gated, exact }. A rough pre-booking estimate; estimate is 0 while gated (the agent has no prior booking yet). Never exact pre-booking. |
boats[].links | object | Agent-only. { mmk, nausys } deeplinks (a platform key is null when the boat isn't on it). |
boats[].similar | boolean | true for nearby/flexible backfill boats appended after the strict matches — the UI groups these under a "Similar boats" divider |
boats[].booked_12m_pct | number | Share of the next 52 weeks covered by a blocking event that is not an option — partner bookings, and owner/calendar blocks too |
boats[].options | array | Holds over the next 12 months, soonest first, at most 8: { start, end, expires } (expires may be null) |
boats[].activity | object | { option, booked, last_option_at } — option / booked describe the selected week (false when no week is set); last_option_at is when the most recent hold on this boat was placed, across the next 12 months |
total | integer | Total boats matching the filters (before limit); similar backfill boats are not counted |
agent | object | The calling agent's { split_percent, commission_gated } — split_percent is your own configured split, set on your agent profile; it is not a standard rate |