API Reference
Complete endpoint reference for the Charter Boats platform
The Charter Boats API is organized by who's calling:
- Discovery API (
/api/ai/*) — public, no key. Conversational search for guests, AI assistants, and agents (also via MCP / Custom GPT). - Agent API (
/api/agent/*) — for approved charter agents. Reveals platform, deeplinks, and per-week activity the public search hides. Needs a logged-in agent session. - Operator API — for operators managing their own listings (boats, photos, pricing, fees, calendar, discounts). Every call carries your key, and reads return only the boats of the companies your account belongs to — to show or sell other operators' boats, use the Discovery API.
- Places & Data — reference data anyone with a key can read (locations, POIs, passages, sea routing, conditions).
Base URL
Authentication
Send your key in the X-API-Key header on every call outside the Discovery API — reads (boats, pricing, fees, locations, POIs, passages, sea routing, features, manufacturers) as well as the writes to your own listings (boats, prices, fees, photos, calendar, discounts):
- No key — the request is stopped by our bot protection before it reaches the API: you get an HTML
403page, not JSON. - A key that isn't real —
401 {"message": "Invalid API key"}. - The iCal feeds (
/calendar/:boatId/export.ics,/calendar/company/:companyId/export.ics) are the exception: calendar apps can't send headers, so they need no key. - The Discovery API (
/api/ai/*) and the MCP server need no key — see below.
Every keyed call is recorded against your account — that is how we can see your traffic when you ask about limits, and tell it apart from an anonymous scraper's. Writes additionally check that you own the boat or company.
Call from your server: browser requests from another website are not supported (no CORS headers), with the single exception of GET /api/locations. Generate your key from Dashboard → Settings → API. See Authentication for the full rules.
Identifying yourself on open endpoints
The Discovery API (/api/ai/*) and /mcp are open: no key needed. A key is optional there, and we recommend it for any production integration. A valid API key is recorded against your account and makes the boat links in the response carry your affiliate ref (when your account has an active affiliate profile), so bookings that start from your integration are credited to you. It also raises your rate limit substantially — see Rate limits — and a missing or invalid key is served exactly like an anonymous call, never a 401. /mcp forwards your key the same way, and an operator's key adds the operator tools.
All /api/ai/* endpoints share one rate-limit budget, and a valid API key has its own, larger allowance — the figures are a ceiling to stay under rather than an exact allowance (see Rate limits); past it you get 429 with a Retry-After header.
Response Format
Endpoints return data directly as JSON. Errors come back as a JSON object — read statusCode and message; statusMessage is not meaningful:
A block by our bot protection (no key sent) is an HTML page with status 403, not this JSON shape.
The boat import endpoint (POST /import/boat) is an exception -- it wraps its response in {"success": true, "boat": {...}}.
Versions
The whole API has one version number. Ask for one with the query parameter api_version (1.0 or 1.1) on any request; every response says which version answered in the X-API-Version header. An unknown value is a 400 naming the supported versions.
Without api_version, a call with an API key, and any call to /api/ai/*, gets 1.0 — the answer the API gave before October 2026 — so an existing integration keeps reading the fields it was built on. New integrations should send api_version=1.1. Endpoints not listed below answer identically in both versions.
These docs show 1.1. The v1.1 / v1.0 switch at the top of every page shows the 1.0 shape instead, on the pages that differ — each says which version it is showing; the rest are marked Same in API v1.0 and v1.1. A docs link can choose too: add ?api_version=1.0.
| Endpoint | 1.0 field | 1.1 field |
|---|---|---|
GET /api/boats row | price_per_day: the charter per day with our auto-applied offer off; original_price_per_day / discount_percentage / discount_label over it; required_extras (per_day, per_booking, per_person, per_person_per_day, from) | price_per_day: the stored list figure; list_price (per day for the boat, all in, and the stay's total); the discount fields are the list figure's |
GET /api/boats/{id} | price_per_day and best_price: the sale day rate; lowest_price_per_day: the same with our auto-applied offer off | price_per_day: the list figure; list_price |
GET /api/boats/availability | dayPrices: each day's sale day rate | dayPrices: each day's list figure; dayDiscounts |
GET /api/boats/{id}/fees | rows without source | rows with source |
GET /api/ai/boats row | discounted_price_per_day, discount_percentage, discount_label (always), required_extras, required_fees, price_summary in the "~… EUR total for the week of …" form; inventory.discounted_price_per_day | list_price, card, rental_type, has_multi_port, crew_cabins, price_summary from the list figure; inventory.per_day |
GET /api/ai/boats/{id} | pricing.ranges[].price_per_day (the sale day rate); discounts.operator_seasonal[].original_price_per_day; deposits inside fees.required; bookable_slots[] without prices | pricing.ranges[].per_day / original_per_day; fees.deposits; stay_price; each slot's due_now, paid_at_pickup, total, deposits, discounts and per_person_day; boat.crew_cabins; optional guests |
GET /api/ai/locations, /{id} | from_price_per_day | from_per_day (the same figure) |
In 1.0 the day rate is the charter part of the 1.1 price, with the auto-applied offer already taken off: rate × days + the required fees + the 45 EUR platform fee adds up to the 1.1 total — subtract no offer again — so a client that sums the parts as before lands on the same price — or a few euros above it, never below: the day rate is rounded up to the whole euro. What 1.0 cannot keep in its old meaning:
price_min/price_max/total_maxcompare the 1.1 list figure in both versions;inventoryprice ranges andfrom_price_per_daycarry the all-in list figure under their old names;- a dated list is priced for the
guestsasked in both versions; an undated list, the price filters and the price sort use the boat's capacity; price_summaryalways uses the "~total" form, never the old per-row "due now" quote;- every figure is the current pricing, the extras processing included;
cabinsonGET /api/ai/boatsrows,GET /api/ai/boats/{id}andGET /api/agent/boatsrows counts guest cabins in both versions, crew cabins not counted, as thecabinsfilter does;crew_cabinssits beside it in 1.1, and in both versions on the agent API.
Discovery API · guests & agents
Public, no key. Compact, fuzzy-matched results tuned for conversation. See the overview.
| Method | Endpoint | Description |
|---|---|---|
GET | /ai/boats | Search boats by location, type, dates, budget |
GET | /ai/locations | Search destinations |
GET | /ai/pois | Find restaurants, fuel, shops near a place |
GET | /ai/routes | Find sailing passages |
GET | /ai/trips | Search curated itineraries |
GET | /ai/content | Search articles, guides, FAQs |
Agent API · approved agents
Agent-authenticated search that reveals source platform, per-yacht deeplinks, per-week availability/options, and a commission preview. Requires a logged-in agent session — see the overview.
| Method | Endpoint | Description |
|---|---|---|
GET | /agent/boats | Dense agent search with platform, deeplinks, and activity |
Operator API · owners & partners
Manage your own listings. Every call carries your X-API-Key.
Boats
| Method | Endpoint | Description |
|---|---|---|
GET | /boats | List boats with filters and search |
GET | /boats/:id | Get boat details |
GET | /boats/availability | Blocked nights for a date range, or one date |
GET | /features | Equipment vocabulary for the features filter |
GET | /manufacturers | List makes |
GET | /manufacturers/:slug | Get one make |
GET | /manufacturers/:slug/models | Models a make sells — values for the makes filter |
GET | /boats/defaults | Get smart defaults for boat forms |
POST | /import/boat | Import a new boat listing |
PATCH | /boats/:id | Update a boat's details |
POST / PATCH / DELETE | /boats/:id/images | Upload, order, hide and delete photos |
POST / PATCH / DELETE | /dashboard/boats/:id/videos[/:videoId] | Upload, hide and delete videos |
GET | /dashboard/boats | List your fleet, unpublished boats included |
DELETE | /boats/:id | Delete a boat |
Pricing & Fees
| Method | Endpoint | Description |
|---|---|---|
GET | /boats/:id/pricing | Resolve effective price per day for a date range |
GET | /boats/:id/prices | List seasonal pricing rules |
POST / PATCH / DELETE | /boats/:id/prices[/:priceId] | Create, change and delete seasonal prices |
POST | /dashboard/pricing/bulk | Set one price on date ranges of many boats |
GET | /boats/:id/fees | List boat fees |
POST / PATCH / DELETE | /boats/:id/fees[/:feeId] | Add, change and delete fees and extras |
Calendar
| Method | Endpoint | Description |
|---|---|---|
POST / DELETE | /dashboard/calendar/blocks[/:id] | Block dates, remove a block |
GET | /dashboard/calendar/availability | Your fleet's bookings, blocks and partner reservations |
GET / POST / DELETE | /dashboard/calendar/sources[/:id] | Connect outside iCal calendars |
GET | /calendar/:boatId/export.ics | Export one boat's calendar as iCal |
GET | /calendar/company/:companyId/export.ics | Export a whole company's calendar as iCal |
Discounts
| Method | Endpoint | Description |
|---|---|---|
GET / POST | /dashboard/discounts | List and create discount codes |
PATCH / DELETE | /dashboard/discounts/:id | Change or end a discount |
Places & Data · public reference
Read-only catalog data you can use to build on the platform. Same rule as the Operator API: send your key on every call.
Locations & POIs
| Method | Endpoint | Description |
|---|---|---|
GET | /locations | List locations with optional filters |
GET | /locations/search | Typeahead search by name |
GET | /locations/:id | Get location details with nearby POIs |
GET | /locations/:id/card | Compact summary: how a place is used, where boats go next, nearest charter base |
GET | /locations/:id/market | Boats available and average weekly price per charter week |
GET | /locations/map | Places inside a map viewport, ranked by vessel traffic |
GET | /pois/search | Search points of interest |
GET | /pois/:id | Get POI details |
Passages & Sea Routing
| Method | Endpoint | Description |
|---|---|---|
GET | /passages | List sailing passages |
GET | /passages/:slug | Get passage details |
GET | /passages/by-location/:id | Get passages from a location |
GET | /searoute/route | Calculate sea route between two points |
Conditions
| Method | Endpoint | Description |
|---|---|---|
| — | — | Sailing conditions / wind (no first-party endpoint yet) |
Looking for booking or content endpoints?
- Booking a boat (reserve + pay) runs through the charter.boats checkout UI, not a public API -- it needs a logged-in guest session and Stripe Elements on the page.
- Articles & FAQs are searchable via the Discovery API's
/ai/content.
HTTP Status Codes
| Code | Description |
|---|---|
200 | Success |
400 | Bad Request -- invalid parameters |
401 | Unauthorized -- the API key isn't valid (messages listed under Authentication) |
403 | Forbidden -- key not allowed to touch this resource (JSON), or no key sent at all: our bot protection answers with an HTML page, not JSON |
404 | Not Found |
409 | Conflict -- duplicate resource |
429 | Too Many Requests -- a rate limit; wait the number of seconds in the Retry-After header. Both the Discovery API and the keyed endpoints answer this, and a keyed daily limit's Retry-After runs to the next 00:00 UTC |
500 | Server Error |
502 | Bad Gateway -- the sea-routing backend failed (/searoute/route) |