Ferry Search API

Ferry Search API

You need to locate and monitor ferries quickly, power accurate ETAs for terminals, and keep operations teams in sync without stitching together multiple data sources. By the end of this guide, you’ll be able to build a ferry search and tracking workflow with vessels-api.com: search by name or identifiers, stream live AIS positions with short-term history, watch nearby traffic around a route or harbor, compute operational analytics, and batch-track your ferry fleet from a single, consistent REST API.

Why a Ferry-Focused Integration Needs a Single, Consistent API

Ferry operations are time-sensitive. Schedules are tight, turnarounds are short, and a few minutes of delay ripple across passengers, terminals, and connecting ground transport. You need:

  • Accurate fuzzy search to find a ferry by commercial name, MMSI, or IMO, including variants and reflagging.
  • Live AIS with short history to understand current speed, course, and whether a vessel is en route or dwelling.
  • Port context: expected arrivals and recent activity to anticipate berth conflicts and announce gate changes.
  • Fleet-level rollups for dispatch boards and command-center views.
  • Optional ESG signals via CII-style emissions estimates for public reporting or internal KPIs.

vessels-api.com offers 18 REST endpoints under one base URL with the same auth header everywhere (X-API-Key), global AIS coverage, and a predictable JSON envelope. That means less glue code, faster “first dashboard,” and simpler reliability testing.

Key Endpoints for Ferries

For a ferry-focused build, start with these endpoints:

  • /vessels/search — find ferries by fuzzy name match or IDs; filter by vessel type, flag, or build year.
  • /vessels/track — live position, last 24–168 hours of tracks, active route, and predicted ETA.
  • /vessels/nearby — traffic around a terminal/route to detect conflicts and give passengers accurate heads-up.
  • /port/expected-arrivals — ETAs into a terminal to plan berth windows, crew handovers, and passenger flows.
  • /vessels/fleet (POST) — batch updates for multiple ferries in a single request for control-room tiles.

All examples below use the same base URL and header:

  • Base URL: https://vessels-api.com/api/V1
  • Header: X-API-Key: YOUR_API_KEY

Search: Find Your Ferry by Name, IMO, or MMSI

Use /vessels/search to resolve a ferry’s identifiers and particulars before you track it. Ferries can have similar names across regions, so filters help narrow the list.

cURL

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/search?query=blue+star&ship_type=Passenger&page=1&per_page=25"

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"vessels": [
{
"imo": "1234567",
"mmsi": "258785000",
"name": "BLUE STAR FERRY",
"flag": "Greece",
"vessel_type": "Passenger",
"gross_tonnage": 27850,
"deadweight_tonnage": 9200,
"year_built": 2010,
"length_m": 180.0,
"width_m": 26.0
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
}

Notes that save time:

  • per_page max is 100; paginate if your ferry brand has multiple sister ships with similar names.
  • year_built_from/year_built_to and flag help isolate the correct hull if the query returns variants.
  • Names are fuzzy-matched; keep your client-side de-duplication simple by anchoring on IMO or MMSI once resolved.

Live Tracking with Short-Term History and Route Context

Once you have an IMO or MMSI, /vessels/track gives your operations dashboard everything it needs: current AIS, last 24–168 hours of trail, active route with ETA, and recent port calls.

cURL

The MMSI 258785000 is a documented fixture you can use during development:

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48&include_route=true&include_predicted_eta=true"

JavaScript (Fetch)

async function trackFerry(mmsi) {
const url = new URL("https://vessels-api.com/api/V1/vessels/track");
url.searchParams.set("mmsi", mmsi);
url.searchParams.set("hours", "48"); // up to 168
url.searchParams.set("include_route", "true");
url.searchParams.set("include_predicted_eta", "true");

const res = await fetch(url.toString(), {
headers: { "X-API-Key": "YOUR_API_KEY" }
});

if (!res.ok) throw new Error(`HTTP ${res.status}`);
const payload = await res.json();

const { vessel, current_position, position_history, route } = payload.data;
return {
name: vessel.name,
mmsi: vessel.mmsi,
lat: current_position.latitude,
lon: current_position.longitude,
speed: current_position.speed_knots, // knots
course: current_position.course_degrees, // degrees
status: current_position.navigational_status,
eta: route?.eta || current_position.eta,
lastFixUtc: current_position.timestamp_utc,
history: position_history // array for polylines on the map
};
}

trackFerry("258785000").then(console.log).catch(console.error);

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"vessel": { "imo": "9122556", "mmsi": "258785000", "name": "FERRY LINE A" },
"current_position": {
"latitude": 37.9423,
"longitude": 23.6291,
"speed_knots": 16.2,
"course_degrees": 118,
"heading_degrees": 120,
"navigational_status": "Under way using engine",
"timestamp_utc": "2026-05-01T09:21:43Z",
"destination": "PIRAEUS",
"eta": "2026-05-01T10:05:00Z"
},
"position_history": [
{ "latitude": 37.9801, "longitude": 23.5632, "speed_knots": 15.8, "course_degrees": 120, "timestamp_utc": "2026-05-01T08:51:43Z" },
{ "latitude": 37.9611, "longitude": 23.5960, "speed_knots": 16.0, "course_degrees": 119, "timestamp_utc": "2026-05-01T09:06:43Z" }
],
"route": {
"departure_port": "HERAKLION",
"departure_time": "2026-05-01T04:00:00Z",
"destination_port": "PIRAEUS",
"eta": "2026-05-01T10:05:00Z",
"distance_nm": 166.2,
"avg_speed_knots": 16.1
},
"last_port_visits": [
{ "port_id": "GRHER", "arrival_time": "2026-04-30T20:00:00Z", "departure_time": "2026-05-01T04:00:00Z" }
]
}
}

What matters for ferries:

  • All timestamps are UTC. Convert for passenger-facing UIs using the target port’s timezone if desired.
  • Speeds are in knots; distances are in nautical miles (nm).
  • Use navigational_status to differentiate dwell vs underway, useful for terminal turnarounds.
  • position_history max window is 168 hours; 24–48 hours usually suffices for map trails.
  • Include include_predicted_eta to align gate announcements and ground transport handoffs.

Proximity: Monitor Ferries and Traffic Near Your Route or Terminal

/vessels/nearby returns vessels within a radius (nautical miles) of a latitude/longitude. For ferries crossing busy straits, overlaying nearby traffic helps dispatch avoid last-minute route conflicts and aids VTS-style views.

cURL

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/nearby?latitude=37.94&longitude=23.62&radius=15&ship_type=Passenger&limit=50"

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"center": { "latitude": 37.94, "longitude": 23.62 },
"radius_nm": 15,
"total": 3,
"vessels": [
{
"imo": "9122556",
"mmsi": "258785000",
"name": "FERRY LINE A",
"ship_type": "Passenger",
"position": { "latitude": 37.9423, "longitude": 23.6291, "timestamp_utc": "2026-05-01T09:21:43Z" },
"distance_nm": 1.2,
"speed_knots": 16.2,
"course_degrees": 118,
"navigational_status": "Under way using engine"
}
]
}
}

Tips:

  • Default radius is 50 nm; max 200 nm. Ferries often need 10–20 nm for corridor awareness.
  • Filter by ship_type=Passenger to focus on ferries and fast cats; omit the filter to capture tugs and cargo that may impact berth availability.
  • Use distance_nm and course_degrees to flag potential head-on or crossing situations in UI color rules.

Plan Berths with Port ETAs and Recent Activity

Terminals need to anticipate inbound ferries, line up ramps, and manage passenger flows. Two endpoints support this: expected arrivals and recent activity.

Expected Arrivals

/port/expected-arrivals lists inbound vessels for a port with ETA and origin. It’s ideal for a simple “Next 6 hours” panel.

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/port/expected-arrivals?port=ARBUE"
{
"status": 200,
"success": true,
"message": "OK",
"data": {
"port_id": "ARBUE",
"port_name": "BUENOS AIRES",
"expected_arrivals": [
{ "mmsi": "258785000", "imo": "9122556", "name": "FERRY LINE A", "vessel_type": "Passenger", "eta": "2026-05-01T10:05:00Z", "departure_port": "HERAKLION" }
],
"total": 1
}
}

Activity Feed

/port/activity lists recent arrivals and departures; wire this into messaging for ramp crews and gate staff.

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/port/activity?port=ARBUE"
{
"status": 200,
"success": true,
"message": "OK",
"data": {
"port_id": "ARBUE",
"port_name": "BUENOS AIRES",
"arrivals": [
{ "mmsi": "258785000", "name": "FERRY LINE A", "arrival_time": "2026-05-01T10:08:00Z", "from_port": "HERAKLION" }
],
"departures": [
{ "mmsi": "258785000", "name": "FERRY LINE A", "departure_time": "2026-05-01T11:00:00Z", "to_port": "HERAKLION" }
]
}
}

Use arrivals and departures to automate announcements and terminal KPIs (turnaround time, punctuality window ±X minutes).

One Call for the Whole Ferry Fleet

For a dispatch board, polling each ferry individually won’t scale. /vessels/fleet lets you fetch positions and routes for multiple vessels in one POST.

cURL

curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"vessels":[{"imo":"9122556"},{"mmsi":"258785000"}],"include_positions":true,"include_routes":true}' \
"https://vessels-api.com/api/V1/vessels/fleet"

Python

import json, requests

API = "https://vessels-api.com/api/V1/vessels/fleet"
HEADERS = {"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"}

payload = {
"vessels": [{"imo": "9122556"}, {"mmsi": "258785000"}],
"include_positions": True,
"include_routes": True
}

r = requests.post(API, headers=HEADERS, data=json.dumps(payload), timeout=20)
r.raise_for_status()
resp = r.json()

summary = resp["data"]["fleet"]
tiles = []
for v in resp["data"]["vessels"]:
tiles.append({
"name": v.get("name"),
"mmsi": v.get("mmsi"),
"imo": v.get("imo"),
"lat": (v.get("position") or {}).get("latitude"),
"lon": (v.get("position") or {}).get("longitude"),
"speed_knots": (v.get("position") or {}).get("speed_knots"),
"destination": (v.get("route") or {}).get("destination_port"),
"eta": (v.get("route") or {}).get("eta")
})

print("Fleet:", summary)
print("Dashboard tiles:", tiles)

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"fleet": { "total_vessels": 2, "vessels_at_sea": 1, "vessels_in_port": 1 },
"vessels": [
{
"imo": "9122556",
"mmsi": "258785000",
"name": "FERRY LINE A",
"position": {
"latitude": 37.9423,
"longitude": 23.6291,
"speed_knots": 16.2,
"course_degrees": 118,
"timestamp_utc": "2026-05-01T09:21:43Z"
},
"route": {
"departure_port": "HERAKLION",
"destination_port": "PIRAEUS",
"eta": "2026-05-01T10:05:00Z",
"distance_nm": 166.2,
"avg_speed_knots": 16.1
}
},
{
"imo": "9000001",
"mmsi": "245000001",
"name": "FERRY LINE B",
"position": null,
"route": null
}
]
}
}

Practical notes:

  • Payload accepts a mixed list of IMO and MMSI objects. Keep your canonical IDs in your DB; pass whichever you have.
  • If a ferry is offline or in port without recent AIS, position may be null. Guard your UI to avoid crashes.
  • Batch this call every 30–60 seconds for control rooms; adjust client-side caching if your wallboard refresh is faster.

Operational Analytics for Ferries

/vessels/analytics aggregates voyage stats over rolling windows. Use this for service punctuality dashboards or to analyze utilization across routes.

cURL

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/analytics?type=vessel&mmsi=258785000&period=7d"

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"type": "vessel",
"mmsi": "258785000",
"imo": "9122556",
"name": "FERRY LINE A",
"period": "7d",
"statistics": {
"total_distance_nm": 1198.4,
"avg_speed_knots": 15.9,
"max_speed_knots": 21.2,
"port_calls_count": 24,
"total_time_in_port_hours": 38.5,
"ports_visited": ["PIRAEUS", "HERAKLION"]
}
}
}

Turn these into route KPIs: distance per day, time-in-port ratios, and port call cadence. For a fleet view, switch to type=fleet with mmsi_list to roll up multiple ferries (see docs for exact list formatting).

Optional: Ferry ESG Snapshot with CII-style Scoring

Passenger operators often report emissions metrics. /vessels/green provides an estimated CO2 footprint and an IMO CII-style letter rating for a defined period.

cURL

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/green?mmsi=258785000&period=30d"

Example JSON (illustrative values)

{
"status": 200,
"success": true,
"message": "OK",
"data": {
"imo": "9122556",
"mmsi": "258785000",
"name": "FERRY LINE A",
"period": "30d",
"distance_nm": 5120.3,
"estimated_emissions": { "co2_tons": 820.5, "co2_per_nm": 0.16 },
"cii": { "score": 12.4, "rating": "C", "year": 2026, "regulation_reference": "IMO MEPC.339(76)" }
}
}

Use this endpoint to enrich internal sustainability dashboards or to automate scheduled monthly reports.

Developer Notes: Auth, Envelopes, Pagination, and Errors

  • Authentication: Every request must include X-API-Key: YOUR_API_KEY. No OAuth or per-endpoint overrides.
  • Response envelope: JSON returns {status, success, message, data}. Parse data.* for the payloads shown above.
  • Units and time: Distances are nautical miles (nm); speeds are knots; timestamps are UTC ISO-8601.
  • Pagination: /vessels/search supports page and per_page (max 100). Use pagination.last_page to stop fetching.
  • Throttling: Handle HTTP 429 by backing off; cache static data like vessel particulars to reduce load.
  • Error map: 400 invalid parameters; 401 missing/invalid key; 404 not found; 422 out-of-range; 500 server error. Keep user-facing messages simple; log the full response for debugging.

End-to-End: Building a Minimal Ferry Ops Panel

Steps

  1. Resolve vessels: Call /vessels/search for each ferry name to lock down IMO/MMSI; store identifiers.
  2. Live map: Poll /vessels/fleet with include_positions=true every 30–60s to render tiles and map markers.
  3. Route and ETA: For selected ferries, call /vessels/track with include_route and include_predicted_eta for details.
  4. Terminal view: Call /port/expected-arrivals and /port/activity to manage gate changes and port-side timelines.
  5. Analytics: Nightly job hits /vessels/analytics for 7d/30d performance cards and utilization charts.
  6. Optional ESG: Monthly job calls /vessels/green for emissions scorecards per ferry.

Copy-Paste Quickstart

cURL: Track One Ferry by MMSI with a 48h History

curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48&include_route=true&include_predicted_eta=true&include_weather=false"

JavaScript: Render a Simple Ferry Card

async function ferryCard(mmsi) {
const base = "https://vessels-api.com/api/V1/vessels/track";
const res = await fetch(`${base}?mmsi=${encodeURIComponent(mmsi)}&hours=24&include_route=true&include_predicted_eta=true`, {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
const json = await res.json();
const d = json.data;

return `
<div class="tile">
<h4>${d.vessel.name} (${d.vessel.mmsi})</h4>
<p>Lat/Lon: ${d.current_position.latitude.toFixed(4)}, ${d.current_position.longitude.toFixed(4)}</p>
<p>Speed: ${d.current_position.speed_knots} kn | Course: ${d.current_position.course_degrees}°</p>
<p>Dest: ${d.current_position.destination || d.route?.destination_port || "—"}</p>
<p>ETA: ${d.route?.eta || d.current_position.eta || "—"} (UTC)</p>
<p>Last fix: ${d.current_position.timestamp_utc}</p>
</div>
`;
}

ferryCard("258785000").then(html => {
document.body.insertAdjacentHTML("beforeend", html);
});

FAQ

How often are positions refreshed?
Positions are based on AIS updates with near real-time refresh. If you need to avoid jitter on wallboards, poll at 30–60s and smooth speed/course on the client.

What if I only know the ferry’s commercial name?
Use /vessels/search with query=name and optionally ship_type=Passenger. Once you confirm the correct match, cache MMSI or IMO and prefer identifier-based calls.

Can I constrain searches by build year or capacity?
Yes. Use year_built_from/year_built_to and min_dwt/max_dwt or min_teu/max_teu if relevant to your fleet filtering needs.

How do I handle missing positions?
If a ferry is in port or AIS is temporarily unavailable, position can be null (especially in batch calls). Guard your UI and display “No recent AIS” with a timestamp of the last known fix if you also store historical data.

What’s the timezone of ETA fields?
ETAs and timestamps are UTC. Convert to local timezones for passenger displays; keep UTC internally for consistency across ports.

Try It and Ship Your Ferry Search and Tracking Stack

Spin up a prototype: search your ferries, render a 24–48h trail, and overlay terminal arrivals. One API key, one base URL, consistent responses. When you’re ready to integrate deeply, see the endpoint details and field definitions in the docs.

Register • Documentation • MCP

Reference Links (non-UTM)

Ready to get started?

Get your API key and start tracking vessels in minutes.

Get API Key

Related posts