Charter Boats API
Passages

Get Passage

Get full details for a specific sailing passage

Endpoint

GET /passages/:slug

Description

Retrieve full details for a sailing passage, including route variants submitted by users, departure/arrival location details with images, and nearby POIs at each end.

Supports a direction parameter to view the return route (swaps departure and arrival).

Authentication

No authentication required. This is a public endpoint. Authenticated users additionally see their own variant votes.

Path Parameters

ParameterTypeDescription
slugstringRoute slug (URL-friendly identifier)

Query Parameters

ParameterTypeRequiredDescription
directionstringNoSet to return to view the passage in reverse

Example Request

curl "https://charter.boats/api/passages/lefkas-to-vasiliki"

Return Direction

curl "https://charter.boats/api/passages/lefkas-to-vasiliki?direction=return"

Example Response

{
  "id": "route-uuid-1",
  "slug": "lefkas-to-vasiliki",
  "title": "Lefkas to Vasiliki",
  "description": "A scenic day sail down the east coast of Lefkada...",
  "distance_nm": 22,
  "difficulty": "easy",
  "typical_duration_hours": 4,
  "rating": 4.8,
  "rating_count": 15,
  "variant_count": 3,
  "geojson": { "type": "LineString", "coordinates": [...] },
  "from_location": {
    "id": 4521,
    "name": "D-Marin Lefkas",
    "country": "Greece",
    "country_code": "GR",
    "lat": 38.8335,
    "lon": 20.7068,
    "harbour_category": "marina",
    "image_url": "https://example.com/marina.jpg"
  },
  "to_location": {
    "id": 4545,
    "name": "Vasiliki",
    "country": "Greece",
    "country_code": "GR",
    "lat": 38.6309,
    "lon": 20.5897,
    "harbour_category": "harbour",
    "image_url": "https://example.com/vasiliki.jpg"
  },
  "variants": [
    {
      "id": "variant-uuid-1",
      "route_id": "route-uuid-1",
      "is_default": true,
      "name": "Coastal Route",
      "description": "Hug the coast for calmer waters",
      "geojson": { "type": "LineString", "coordinates": [...] },
      "distance_nm": 22,
      "upvote_count": 8,
      "downvote_count": 1,
      "user": {
        "id": "user-uuid-1",
        "name": "Captain Alex"
      },
      "created_at": "2026-01-15T10:00:00Z"
    },
    {
      "id": "variant-uuid-2",
      "route_id": "route-uuid-1",
      "is_default": false,
      "name": "Open Water Route",
      "description": "Direct route across the channel",
      "geojson": { "type": "LineString", "coordinates": [...] },
      "distance_nm": 18,
      "upvote_count": 3,
      "downvote_count": 2,
      "user": {
        "id": "user-uuid-2",
        "name": "Sailor Jane"
      }
    }
  ],
  "user_votes": {
    "variant-uuid-1": 1
  },
  "from_pois": [
    {
      "distance_meters": 120,
      "poi": {
        "id": "poi-uuid-1",
        "name": "Marina Fuel Station",
        "category": "fuel",
        "subcategory": null,
        "rating": 4.2
      }
    }
  ],
  "to_pois": [
    {
      "distance_meters": 200,
      "poi": {
        "id": "poi-uuid-3",
        "name": "Vasiliki Taverna",
        "category": "restaurant",
        "subcategory": "taverna",
        "rating": 4.6
      }
    }
  ],
  "is_reversed": false
}

Response Fields

FieldTypeDescription
idstringRoute ID (UUID)
slugstringURL slug
titlestringRoute title
descriptionstring|nullRoute description
distance_nmnumber|nullDistance in nautical miles
difficultystring|nullDifficulty level
typical_duration_hoursnumber|nullEstimated sailing time
ratingnumber|nullAverage rating
rating_countnumber|nullNumber of ratings
variant_countnumber|nullNumber of route variants
geojsonobject|nullDefault route geometry
from_locationobjectDeparture location with image
to_locationobjectArrival location with image
variantsarrayRoute variants sorted by default first, then by votes
variants[].userobjectVariant author (id and name)
variants[].upvote_countnumberNumber of upvotes
variants[].downvote_countnumberNumber of downvotes
user_votesobjectAuthenticated user's votes (variant_id to vote mapping: 1 = up, -1 = down). Empty if not logged in.
from_poisarrayUp to 5 nearest POIs at departure (with distance)
to_poisarrayUp to 5 nearest POIs at arrival (with distance)
is_reversedbooleantrue when direction=return was used

Notes

  • When direction=return is set, from_location and to_location are swapped, along with from_pois and to_pois.
  • user_votes is only populated for authenticated users. Each key is a variant ID, and the value is 1 (upvote) or -1 (downvote).

Error Responses

404 Not Found

{
  "statusCode": 404,
  "message": "Route not found"
}

On this page