Charter Boats
Charter Boats API

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

https://charter.boats/api

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):

curl "https://charter.boats/api/boats?company_slug=your-company&type=catamaran&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"
 
curl -X POST "https://charter.boats/api/import/boat" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
  • No key — the request is stopped by our bot protection before it reaches the API: you get an HTML 403 page, 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.

curl "https://charter.boats/api/ai/boats?l=Split" \
  -H "X-API-Key: YOUR_API_KEY"

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:

{
  "error": true,
  "url": "https://charter.boats/api/boats/no-such-boat",
  "statusCode": 404,
  "statusMessage": "Server Error",
  "message": "Boat not found"
}

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.

Endpoint1.0 field1.1 field
GET /api/boats rowprice_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 offprice_per_day: the list figure; list_price
GET /api/boats/availabilitydayPrices: each day's sale day ratedayPrices: each day's list figure; dayDiscounts
GET /api/boats/{id}/feesrows without sourcerows with source
GET /api/ai/boats rowdiscounted_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_daylist_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 pricespricing.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_dayfrom_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_max compare the 1.1 list figure in both versions;
  • inventory price ranges and from_price_per_day carry the all-in list figure under their old names;
  • a dated list is priced for the guests asked in both versions; an undated list, the price filters and the price sort use the boat's capacity;
  • price_summary always uses the "~total" form, never the old per-row "due now" quote;
  • every figure is the current pricing, the extras processing included;
  • cabins on GET /api/ai/boats rows, GET /api/ai/boats/{id} and GET /api/agent/boats rows counts guest cabins in both versions, crew cabins not counted, as the cabins filter does; crew_cabins sits 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.

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.

MethodEndpointDescription
GET/agent/boatsDense agent search with platform, deeplinks, and activity

Operator API · owners & partners

Manage your own listings. Every call carries your X-API-Key.

Boats

MethodEndpointDescription
GET/boatsList boats with filters and search
GET/boats/:idGet boat details
GET/boats/availabilityBlocked nights for a date range, or one date
GET/featuresEquipment vocabulary for the features filter
GET/manufacturersList makes
GET/manufacturers/:slugGet one make
GET/manufacturers/:slug/modelsModels a make sells — values for the makes filter
GET/boats/defaultsGet smart defaults for boat forms
POST/import/boatImport a new boat listing
PATCH/boats/:idUpdate a boat's details
POST / PATCH / DELETE/boats/:id/imagesUpload, order, hide and delete photos
POST / PATCH / DELETE/dashboard/boats/:id/videos[/:videoId]Upload, hide and delete videos
GET/dashboard/boatsList your fleet, unpublished boats included
DELETE/boats/:idDelete a boat

Pricing & Fees

MethodEndpointDescription
GET/boats/:id/pricingResolve effective price per day for a date range
GET/boats/:id/pricesList seasonal pricing rules
POST / PATCH / DELETE/boats/:id/prices[/:priceId]Create, change and delete seasonal prices
POST/dashboard/pricing/bulkSet one price on date ranges of many boats
GET/boats/:id/feesList boat fees
POST / PATCH / DELETE/boats/:id/fees[/:feeId]Add, change and delete fees and extras

Calendar

MethodEndpointDescription
POST / DELETE/dashboard/calendar/blocks[/:id]Block dates, remove a block
GET/dashboard/calendar/availabilityYour fleet's bookings, blocks and partner reservations
GET / POST / DELETE/dashboard/calendar/sources[/:id]Connect outside iCal calendars
GET/calendar/:boatId/export.icsExport one boat's calendar as iCal
GET/calendar/company/:companyId/export.icsExport a whole company's calendar as iCal

Discounts

MethodEndpointDescription
GET / POST/dashboard/discountsList and create discount codes
PATCH / DELETE/dashboard/discounts/:idChange 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

Passages & Sea Routing

MethodEndpointDescription
GET/passagesList sailing passages
GET/passages/:slugGet passage details
GET/passages/by-location/:idGet passages from a location
GET/searoute/routeCalculate sea route between two points

Conditions

MethodEndpointDescription
——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

CodeDescription
200Success
400Bad Request -- invalid parameters
401Unauthorized -- the API key isn't valid (messages listed under Authentication)
403Forbidden -- key not allowed to touch this resource (JSON), or no key sent at all: our bot protection answers with an HTML page, not JSON
404Not Found
409Conflict -- duplicate resource
429Too 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
500Server Error
502Bad Gateway -- the sea-routing backend failed (/searoute/route)