Ferryscanner APIferryscanner.com ↗
Search ferry ports by name and retrieve full-day departure schedules with fares, vessel details, and cancellation terms via the ferryscanner.com API.
What is the Ferryscanner API?
The ferryscanner.com API exposes 2 endpoints that cover ferry port lookup and full-day departure search. Use search_ports to resolve port codes from city, island, or country name fragments — including Greek, Italian, and English spellings — then pass those codes to search_ferries to retrieve every one-way departure on a given date, complete with per-passenger-type pricing, vessel details, duration, and cancellation policy.
curl -X GET 'https://api.parse.bot/scraper/55480f0a-3cd2-4cf3-8dcd-66426bdb3f26/search_ports?query=napoli' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace ferryscanner-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: FerryScanner SDK — find ports, search trips, inspect pricing."""
from parse_apis.ferryscanner_com_api import FerryScanner, PortNotFound
client = FerryScanner()
# Search for departure ports matching "napoli"
departure_port = client.ports.search(query="napoli", limit=5).first()
if departure_port is None:
print("No ports found for 'napoli'")
else:
print(f"Departure: {departure_port.name} ({departure_port.port_code}), group={departure_port.is_group}")
# Search one-way trips from Naples to Capri (PRJ)
try:
for trip in departure_port.trips.search(arrival="PRJ", date="2026-10-22", limit=3):
adult_price = trip.prices.adult
print(
f"{trip.departure_datetime} {trip.company_name} "
f"{trip.departure_port_name} → {trip.arrival_port_name} "
f"({trip.duration}) "
f"{adult_price.total} {adult_price.currency}"
)
# Capacity overview
if trip.capacity.seat.supported:
print(f" Seats available: {trip.capacity.seat.available}")
if trip.cancellation.non_refundable:
print(" Non-refundable")
except PortNotFound:
print("Unknown port code — check search_ports results")
print("exercised: ports.search / port.trips.search / PortNotFound")
Finds ferry ports and port groups whose name, alternative spelling, port code or country contains the query text (case-insensitive; Italian/Greek/English spellings such as 'napoli' match 'Naples'). Returns a single page of at most 50 matching ports with total_matches and a truncated flag when more matched. Each port carries port_code, the value accepted by search_ferries as departure/arrival; a group entry (is_group=true, e.g. 'Naples (All Ports)') searches all its child_port_codes at once. A query matching nothing returns an empty ports list with total_matches 0.
| Param | Type | Description |
|---|---|---|
| queryrequired | string | Free-text port, city, island or country name fragment (e.g. napoli). |
{
"type": "object",
"fields": {
"ports": "array of matching ports: port_code (use in search_ferries), name, country_code, country, is_group, child_port_codes (port codes covered by a group entry, empty for a single port), timezone, latitude, longitude",
"truncated": "boolean, true when more than 50 ports matched and only the first 50 are returned",
"total_matches": "integer count of all matches before the 50-item cap"
},
"sample": {
"data": {
"ports": [
{
"name": "Naples (All Ports)",
"country": "Italy",
"is_group": true,
"latitude": 40.837513,
"timezone": "Europe/Rome",
"longitude": 14.24992,
"port_code": "NAPO",
"country_code": "IT",
"child_port_codes": [
"BEV",
"NAP",
"POZ",
"MER",
"TDG",
"PRT",
"MPR"
]
},
{
"name": "Naples Beverello",
"country": "Italy",
"is_group": false,
"latitude": 40.837513,
"timezone": "Europe/Rome",
"longitude": 14.24992,
"port_code": "BEV",
"country_code": "IT",
"child_port_codes": []
}
],
"truncated": false,
"total_matches": 4
},
"status": "success"
}
}About the Ferryscanner API
Port Lookup with search_ports
The search_ports endpoint accepts a free-text query parameter and returns up to 50 matching ports. Each result includes a port_code (the key input for search_ferries), name, country_code, country, an is_group flag, and child_port_codes for port groups that aggregate multiple physical piers. When more than 50 ports match, truncated is set to true and total_matches tells you the full count. Spelling variants like napoli, Napoli, and Naples all resolve to the same port.
Ferry Schedule Retrieval with search_ferries
The search_ferries endpoint takes a departure port code, an arrival port code, and a date (ISO 8601 YYYY-MM-DD local to the departure port). It returns the complete day's schedule in a single response — no pagination. Each entry in the trips array carries a trip_id, company_code, company_name, company_logo, operating_company_name, vessel name, departure and arrival datetimes, trip duration in ISO 8601 format, and structured per-passenger-type fare data with capacity and cancellation terms.
Response Shape and Practical Notes
Trips are sorted by departure_datetime. The top-level response also echoes back the requested departure, arrival, and date fields, plus a total_trips integer so you can quickly check how many sailings exist without iterating the array. Port codes for groups (e.g. a city port that covers multiple terminals) include child codes, which is useful when you need to map a user-supplied city name to the precise terminal used by a specific operator.
The Ferryscanner API is a managed, monitored endpoint for ferryscanner.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when ferryscanner.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official ferryscanner.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a ferry price-comparison widget by querying search_ferries for the same route across multiple dates and comparing the per-passenger fares.
- Populate an autocomplete field for departure and arrival ports using search_ports with partial city or island names.
- Display real-time ferry schedules for a travel itinerary app, showing departure times, duration, and vessel names.
- Check cancellation terms programmatically before booking, using the cancellation fields in each trip object.
- Aggregate capacity data across sailings on a route to flag low-availability departures.
- Resolve Greek island names entered by users (in English, Greek, or Italian transliteration) to canonical port codes before querying schedules.
- Monitor fare changes over time on a specific route by storing search_ferries responses for the same date and comparing passenger-type prices.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does ferryscanner.com offer an official developer API?+
What pricing detail does search_ferries return per trip?+
Does search_ferries support multi-day or return journey queries?+
search_ferries endpoint covers a single travel date for a one-way trip between two ports. To compare fares across multiple dates or build a return journey, call the endpoint once per date or direction. You can fork this API on Parse and revise it to add a helper endpoint that batches multiple date queries.Can I retrieve routes that involve intermediate stops or multi-leg journeys?+
What happens when a port name matches more than 50 results in search_ports?+
truncated to true and returns the actual total in total_matches. Refine your query string — for example, adding a country name or more letters from the port name — to narrow results below the 50-item cap.