If you run vehicles-on-wheels logistics or port operations, one Ro-Ro vessel missing its window can ripple through inland trucking, rail slots, and yard allocation. By the end of this post, you will be able to search for Ro-Ro vessels, live-track a hull with historical positions and voyage data, and scan for all vessels near a terminal using vessels-api.com — with copy-paste cURL and Python/JavaScript that you can ship into your Transportation systems today.
What you can build for Ro-Ro operations
Using vessels-api.com you can wire the essentials for a roll-on/roll-off fleet or terminal:
- Locate Ro-Ro hulls by name, IMO, or MMSI with /vessels/search, narrowing by flag, build year, or capacity bands.
- Live track a specific MMSI with /vessels/track, including last known position, 24–168h track history, route, ETA, and last port calls.
- Detect all vessels near your berth or pilot station with /vessels/nearby for proactive tug/pilot planning.
- Batch-fetch your whole fleet’s latest positions and routes with /vessels/fleet in a single POST.
- Quantify voyage performance with /vessels/analytics for on-time and distance KPIs.
Why this API fits Transportation workflows:
- 18 REST endpoints spanning vessel search, live tracking, fleet ops, port intelligence, emissions, and a premium real-time AIS feed.
- Single X-API-Key header for auth across the entire surface area; one base URL.
- Consistent JSON envelope: {status, success, message, data} for predictable parsing.
- Global AIS with near real-time refresh; designed to scale from indie dashboards to enterprise control towers.
Base URL, authentication, and the response envelope
All endpoints live at https://vessels-api.com/api/V1. Send your key in the X-API-Key header. The API returns a consistent top-level JSON envelope:
{
"status": 200,
"success": true,
"message": "OK",
"data": {
"vessel": {
"imo": "9122556",
"mmsi": "258785000",
"name": null
},
"current_position": {
"latitude": 53.33708,
"longitude": 7.17993,
"speed_knots": 0,
"course_degrees": 212,
"heading_degrees": null,
"navigational_status": 5,
"timestamp_utc": "2017-01-24T04:07:24+00:00",
"age_minutes": 5097380,
"destination": null,
"eta": null
},
"predicted_eta": null,
"position_history": [],
"route": {
"departure_port": "HERACLIO",
"departure_time": "2026-04-27T21:35:36+00:00",
"destination_port": "HERACLIO",
"eta": "2026-04-30T09:00:00+00:00",
"distance_nm": null,
"avg_speed_knots": 17.1
},
"last_port_visits": [
{
"port_id": "156",
"port_name": "EMDEN",
"arrival_time": "2026-07-30T13:00:10+00:00",
"departure_time": null,
"duration_hours": null
},
{
"port_id": "10",
"port_name": "HERACLIO",
"arrival_time": "2026-04-20T12:00:00+00:00",
"departure_time": "2026-04-23T08:00:00+00:00",
"duration_hours": 68
}
],
"weather": null
}
}
HTTP methods: GET for all endpoints except /vessels/fleet which uses POST with a JSON body. Error codes include 400 (invalid parameter), 401 (missing/invalid key), 404 (not found), 422 (out of range), 429 (rate limit), and 500 (server error).
Quick links: Register · Documentation · MCP
Search: find Ro-Ro vessels by name, IMO, MMSI, or filters
Use /vessels/search to seed your Ro-Ro roster or to let dispatchers resolve identifiers quickly. You can fuzzy search by name or directly query by IMO/MMSI. Add filters like ship_type, flag, DWT/TEU ranges, and built years. Pagination supports page and per_page (max 100).
cURL example: fuzzy name search with a Ro-Ro type hint
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"
What to expect in the response
Fields you’ll typically map:
- imo, mmsi, name: stable identifiers for subsequent calls.
- vessel_type: match “Ro-Ro” variants in your own taxonomy.
- deadweight_tonnage, gross_tonnage, length_m, width_m: constraints for berth assignment logic.
Track: live position, voyage, and history for a Ro-Ro MMSI
/vessels/track returns the current position, up to 168 hours of history (hours parameter), voyage route, predicted ETA, and last port visits. For Transportation, this is the spine of ETD/ETA tracking, tug/pilot scheduling, and shore-side resource planning.
Official cURL sample (copy-paste)
Official JSON sample (verbatim)
What the fields mean for Transportation teams
- current_position.timestamp_utc is UTC ISO-8601; use it to validate data recency.
- speed_knots, course_degrees, and navigational_status support simple underway/berthed logic.
- route includes departure/destination, ETA, and average speed — helpful for ECDIS-lite dashboards.
- last_port_visits lets you enrich operational history and detect idle time or frequent calls.
Python example: track a Ro-Ro and compute delay risk
import requests
from datetime import datetime, timezone
API_KEY = "YOUR_API_KEY"
URL = "https://vessels-api.com/api/V1/vessels/track"
params = {"mmsi": "258785000", "hours": 48}
headers = {"X-API-Key": API_KEY}
r = requests.get(URL, params=params, headers=headers, timeout=20)
r.raise_for_status()
payload = r.json()
if not payload.get("success"):
raise RuntimeError(payload.get("message"))
data = payload["data"]
v = data["vessel"]
pos = data["current_position"]
route = data.get("route", {})
print(f"MMSI {v['mmsi']} IMO {v['imo']}")
ts = datetime.fromisoformat(pos["timestamp_utc"].replace("Z", "+00:00"))
age_minutes = (datetime.now(timezone.utc) - ts).total_seconds() / 60.0
print(f"Last AIS fix age (min): {age_minutes:.1f}")
print(f"Speed (kn): {pos['speed_knots']} Course: {pos['course_degrees']}")
eta = route.get("eta") or pos.get("eta")
if eta:
eta_dt = datetime.fromisoformat(eta.replace("Z", "+00:00"))
print(f"ETA: {eta_dt.isoformat()} at {route.get('destination_port')}")
else:
print("ETA unavailable, fall back to average speed heuristics.")
# Simple delay flag: no motion + old AIS fix + within 24h of ETA
delay_flag = (
pos["speed_knots"] == 0 and eta and age_minutes > 180 and
(datetime.fromisoformat(eta.replace("Z", "+00:00")) - datetime.now(timezone.utc)).total_seconds() < 86400
)
print(f"Delay risk: {delay_flag}")
Nearby: scan a Ro-Ro terminal’s approaches
/vessels/nearby returns all vessels within a radius (nautical miles) of a lat/lon point, with optional filtering by ship_type and a result limit. Ideal for pilots, tug dispatch, and berth teams to see what’s inbound to ro-ro ramps.
cURL example: 30 NM around a terminal
Response shape to integrate
Key fields:
- distance_nm and speed_knots: build a simple inbound ETA if you don’t call /vessels/track per vessel.
- limit caps response size; radius max is 200 NM.
JavaScript example: map the nearby scan
async function fetchNearbyRoRo(lat, lon, radiusNm = 30) {
const url = new URL("https://vessels-api.com/api/V1/vessels/nearby");
url.searchParams.set("latitude", lat);
url.searchParams.set("longitude", lon);
url.searchParams.set("radius", radiusNm);
url.searchParams.set("ship_type", "Ro-Ro");
url.searchParams.set("limit", 50);
const res = await fetch(url.toString(), {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
if (!json.success) throw new Error(json.message);
return json.data.vessels.map(v => ({
id: v.mmsi || v.imo,
name: v.name,
lat: v.position.latitude,
lon: v.position.longitude,
speed: v.speed_knots,
course: v.course_degrees,
distance: v.distance_nm,
type: v.ship_type
}));
}
// Example usage:
fetchNearbyRoRo(-34.6, -58.38).then(list => console.log("Nearby Ro-Ro:", list));
Fleet: batch positions and routes in a single call
If you manage multiple Ro-Ro hulls, /vessels/fleet aggregates current positions and (optionally) routes for multiple identifiers. This reduces N calls into 1 and simplifies dashboard refresh cycles.
cURL example (POST JSON body)
Sample response fields
Implementation notes:
- Body supports a mix of {imo} and {mmsi} objects.
- Toggle include_positions and include_routes per your bandwidth and UI needs.
Analytics: voyage KPIs for Ro-Ro reliability
/vessels/analytics aggregates distance, speed stats, port calls, and dwell time. Use it to score on-time performance, benchmark turn times, or feed SLA dashboards.
cURL example (7-day window)
Response structure
How to apply it:
- total_distance_nm and avg_speed_knots: validate route adherence vs. planned profiles.
- port_calls_count and total_time_in_port_hours: assess terminal throughput and schedule slack.
Port-side context: congestion snapshot
When a Ro-Ro is inbound, terminal state matters. /ports/congestion returns a real-time snapshot (vessels in anchorage/at berth) and recent wait-time statistics for a port by UN/LOCODE (e.g., ARBUE, SGSIN, NLRTM). Use period=24h|3d|7d to change the comparison window.
cURL example
Response fields include snapshot.vessels_in_anchorage, snapshot.vessels_at_berth and statistics.avg_wait_time_hours_last_7d, max_wait_time_hours_last_7d, avg_berth_time_hours_last_7d, port_calls_count. Combine this with /vessels/track ETA to decide whether to pace pilotage or hold at anchorage.
Implementation tips that save time
- Units and time: distances are nautical miles; speeds are knots; timestamps are UTC ISO-8601. Always parse as timezone-aware.
- Null handling: predicted_eta, weather, route.distance_nm, and vessel.name can be null. Always branch safely.
- History bounds: /vessels/track hours defaults to 24 and maxes at 168. Don’t request more than you visualize.
- Pagination: /vessels/search returns pagination with per_page up to 100. Cache current pages in your UI for quick back/forward.
- Radius and limits: /vessels/nearby radius defaults to 50 NM and maxes at 200. Use limit to prevent map clutter.
- HTTP errors: differentiate 404 “not found” (bad identifier or no data) from 422 (parameter out of range). Use message for user feedback.
- Envelope consistency: always check success before reading data. Log message for observability.
- Batching: prefer /vessels/fleet over looping /vessels/track for periodic dashboards to reduce network overhead.
Putting it together: a minimal Ro-Ro control tile
A common Transportation pattern is a “control tile” per vessel combining identity, latest AIS fix, ETA, and a proximity indicator.
- Lookup MMSI/IMO with /vessels/search when a dispatcher types a name.
- Ping /vessels/track for current_position, route. If predicted_eta is available, prefer it.
- Optionally, call /vessels/nearby at your berth lat/lon to show “n vessels within 10 NM”.
Cache the last successful track payload for 2–5 minutes depending on your refresh budget and UI latency tolerance.
Security and environment
- Always keep X-API-Key server-side for web apps. For client-side demos, proxy calls via your backend.
- Time out HTTP calls explicitly; e.g., 10–20s in Python/Node fetch to avoid dangling requests in UIs.
- Log both HTTP status and the {status, message} from the envelope for quick diagnostics.
ESG and compliance note for Ro-Ro operators
While this article focuses on search/track/nearby flows, Ro-Ro fleets under ESG mandates can query /vessels/green for IMO CII scoring (A–E) with period windows like 24h|7d|30d|1y. Pair emissions scores with /vessels/analytics to correlate efficiency with port dwell or routing choices. See the docs for full field details.
FAQ
Q1: Do I need different auth for each endpoint?
A1: No. All endpoints use the same X-API-Key header against the common base URL.
Q2: What timezone are timestamps in?
A2: All timestamps are in UTC, ISO-8601 formatted. Parse as timezone-aware datetimes.
Q3: How far back can I request position history?
A3: /vessels/track supports hours up to 168 (7 days). The default is 24 hours if not specified.
Q4: Can I filter the nearby scan to only Ro-Ro vessels?
A4: Yes. Use the ship_type filter on /vessels/nearby. Combine with limit to cap response size.
Q5: What’s the difference between route.eta and predicted_eta?
A5: route.eta reflects the voyage plan if available; predicted_eta is a model-derived estimate when enabled. Check both and prefer predicted_eta when present.
Next steps
Wire these endpoints into your Transportation stack to give planners, port captains, and dispatch real-time visibility on your Ro-Ro lanes. Start with the official Documentation, then grab an API key and ship your first call in minutes: Register. For advanced integrations and toolchains, explore the MCP resources.





