Charter Boats
Charter Boats API
AI Integrations

AI Integrations Overview

Use Charter Boats data through Custom GPTs, MCP servers, and direct API calls

Charter Boats exposes a set of AI-optimized endpoints under /api/ai/* designed for use by LLM-based integrations. The read endpoints are public (no key), and the same endpoints are surfaced three ways:

  1. MCP Server -- A Model Context Protocol server at https://charter.boats/mcp that works in Claude.ai, Claude Desktop, ChatGPT Apps, Cursor, and any MCP-compatible client. Provides rich UI widgets for boats and locations.
  2. Custom GPT -- A ChatGPT Action that uses an OpenAPI schema to search boats, locations, POIs, routes, trips, and content.
  3. In-browser agents (WebMCP) -- When an AI agent loads a charter.boats page, the site registers the same ten tools on navigator.modelContext, so browser-based agents (Chrome's built-in AI, ChatGPT Atlas, Claude in Chrome, Gemini) can call them directly. Nothing to install -- it's served by the page.

All three call the same underlying /api/ai/* endpoints, which are optimized for AI consumption: fuzzy location matching, compact response shapes, an explained answer whenever a search comes back empty, and rate limiting tuned for conversational use. You can also call the endpoints directly over HTTP.

Building for an LLM crawler instead of a tool-calling agent? https://charter.boats/llms.txt gives a plain-text map of the site for model consumption.

Base URL

All AI endpoints are relative to:

https://charter.boats/api/ai

Authentication

No authentication required. The read endpoints below are open to any caller, with or without a key.

A key is optional. If you send your API key in the X-API-Key header (see identifying yourself), the call is recorded against your account, and boat links in the response — boats[].url from /ai/boats and url from /ai/boats/{id} — carry your affiliate ref when your account has an active affiliate profile, so bookings that start from your integration are credited to you. Nothing else about the response changes. A missing or invalid key is served exactly like an anonymous call — never a 401.

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

Rate Limits

All /api/ai/* endpoints draw on one shared budget per client — a boat search and a location lookup count against the same allowance.

SourceLimit
Custom GPT requests (counted per OpenAI user)30 requests / 10 minutes
All other clients (counted per IP)60 requests / 10 minutes

Rate-limited responses return 429 Too Many Requests with a Retry-After header (seconds). Treat the figures as a ceiling to stay under rather than an exact allowance.

Available Endpoints

Zero results

A search that finds nothing never comes back as a bare empty array. /ai/boats, /ai/locations, /ai/pois, /ai/routes, /ai/trips and /ai/content all add the same block beside their (empty) result list:

{
  "routes": [],
  "no_results": {
    "searched": "passages touching Lefkas, Marina Sivota",
    "why": "We publish written passages only for pairs that have one, so this returns nothing even when both places exist and boats sail between them.",
    "try_next": [
      "search_locations with `from`=<location id> — where boats were actually recorded sailing from there"
    ]
  },
  "note": "Nothing matched passages touching Lefkas, Marina Sivota. We publish written passages only for pairs that have one, so this returns nothing even when both places exist and boats sail between them. Try: search_locations with `from`=<location id> — where boats were actually recorded sailing from there."
}
FieldDescription
no_results.searchedWhat was actually run, after resolution -- the interpretation of your input, not the raw string you sent.
no_results.whyWhich constraint emptied it -- the place, the dates, a filter, or nothing indexed. Different causes want different retries.
no_results.try_nextConcrete next calls, most likely to work first, written in tool terms.
noteOne sentence generated from the three fields above, for clients that only skim. It never says anything the block does not.

searched is the interpretation, not the input: a place is resolved first (by the one resolver behind boat search), and the line names what it resolved to.

Where a term could not be resolved at all, the endpoint also names it under its own key -- location_unresolved (boats, POIs, trips, and an unusable location_id on routes), region_unresolved and from_unresolved (locations, routes). An unresolved place is never silently widened into a worldwide search: no search is run at all.

Custom GPT

The Custom GPT uses an OpenAPI 3.1 schema that exposes the endpoints above as ChatGPT Actions, pointed at https://charter.boats/api/ai.

To set up your own Custom GPT using Charter Boats data:

  1. Create a new GPT in ChatGPT
  2. Add a new Action
  3. Paste in the OpenAPI schema -- it is not published as a file, so request it through the contact page
  4. No authentication is needed

GPT Conversation Handoff

When requests come from a Custom GPT, the server reads the openai-conversation-id header and uses it to hand the conversation over to charter.boats:

  • Link tagging -- links on https://charter.boats/... in the response (search_url, location, POI, route, trip and article URLs) get ?oid=<conversation_id> appended. Boat share links (https://chrtr.me/...) are left as they are.
  • Context handoff -- boat searches made from the GPT are stored against that conversation. When the guest follows an ?oid= link, the on-site chat reads the latest boat search back (location, boat type, guests, dates, budget) and continues from it instead of starting cold. This lookup (GET /ai/gpt-context?oid=…) exists for the site's own chat; it is not a tool for the GPT to call.

MCP Server

The MCP Server provides the same data through the Model Context Protocol with rich HTML widgets for boat and location results. See the dedicated page for details.

On this page