You need to know whether a car carrier is near a port, how fast it’s approaching, when it will berth, and whether congestion might blow up your schedule. By the end of this guide, you’ll be able to: find car carriers within a radius of any port, drill into a specific vessel’s live track and route, check expected arrivals and congestion, and wire these into a small, production-ready integration using the vessels-api.com REST endpoints.
What we’ll build for car carriers near a port
This walkthrough focuses on roll-on/roll-off (Ro-Ro) car carriers and covers four high-signal endpoints you can stitch together quickly:
- GET /vessels/nearby — find car carriers within N nautical miles of a port’s coordinates
- GET /vessels/track — inspect a target vessel’s live position, route, and recent port calls
- GET /port/expected-arrivals — list scheduled/declared arrivals with ETAs and origin ports
- GET /ports/congestion — snapshot of anchorage/berth counts and wait-time statistics
All endpoints share one base URL and one header-based API key:
- Base URL: https://vessels-api.com/api/V1
- Auth: X-API-Key: YOUR_API_KEY
- Uniform JSON envelope: {status, success, message, data}
Links you’ll want handy: Register, Documentation, MCP.
1) Find car carriers near a port with /vessels/nearby
Start by turning a port’s coordinates into a proximity query. If your app already stores port lat/lon, pass them directly. If you need a lookup, use GET /ports to fetch the catalog and select the port you care about, then feed its coordinates into /vessels/nearby.
cURL: car carriers within 20 NM
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"
Key query parameters:
- latitude, longitude — center point (decimal degrees)
- radius — nautical miles (default 50, max 200)
- ship_type — filter for “Vehicles Carrier” to narrow to Ro-Ro car carriers
- limit — max vessels to return (default 50)
Example JSON (truncated)
{
"status": 200,
"success": true,
"message": "OK",
"data": {
"vessel": {
"imo": "9122556",
"mmsi": "258785000",
"name": null
},
"current_position": {
"latitude": 53.33708,
"longitude": 7.17993,
"position_precision": "precise",
"position_accuracy_nm": null,
"speed_knots": 0,
"course_degrees": 212,
"heading_degrees": null,
"navigational_status": 5,
"timestamp_utc": "2017-01-24T04:07:20+00:00",
"age_minutes": 5153720,
"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": null,
"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
}
}
What to read:
- vessels[].distance_nm — great for list sorting and “near me” UIs
- vessels[].speed_knots and course_degrees — quickly infer approach vs. loitering
- vessels[].navigational_status — AIS numeric codes; 5 typically indicates moored/anchored states
Python example: show the nearest car carrier
import requests
from datetime import datetime, timezone
API_BASE = "https://vessels-api.com/api/V1"
API_KEY = "YOUR_API_KEY"
params = {
"latitude": 1.264,
"longitude": 103.84,
"radius": 20,
"ship_type": "Vehicles Carrier",
"limit": 50
}
resp = requests.get(f"{API_BASE}/vessels/nearby", headers={"X-API-Key": API_KEY}, params=params)
resp.raise_for_status()
payload = resp.json()
vessels = payload["data"]["vessels"]
if not vessels:
print("No car carriers within radius.")
else:
nearest = sorted(vessels, key=lambda v: v.get("distance_nm", 1e9))[0]
name = nearest.get("name") or f"IMO {nearest.get('imo')}"
dist = nearest.get("distance_nm")
spd = nearest.get("speed_knots")
ts = nearest["position"]["timestamp_utc"]
print(f"Nearest: {name} at {dist} NM, {spd} kn (as of {ts})")
Notes that save time:
- All times are UTC ISO-8601 strings (e.g., 2026-08-10T10:21:30+00:00). Display with local port time by converting using the port’s timezone from GET /ports or GET /ports/data.
- Cache nearby lists for a short TTL if you’re polling; AIS refresh is near real time but you usually don’t need sub-minute UI updates.
- Cap radius at 200 NM; the endpoint enforces it (422 on out-of-range).
2) Drill down: live track and route for a target car carrier
Once you’ve picked a candidate mmsi or imo, call GET /vessels/track to fetch the current_position, up to 168 hours of position_history, and route with predicted ETA. The following is the official sample for mmsi 258785000 (keep the request identical when testing):
Official cURL sample (copy/paste)
Official JSON (verbatim)
What you’ll actually use:
- current_position.latitude/longitude, speed_knots, course_degrees — place a marker and derive motion
- route.departure_port, destination_port, avg_speed_knots — populate voyage context and ETA models
- last_port_visits[] — show a compact history in your UI; useful for customs and line logistics
Python: turn a track into a “minutes from pilot station” estimate
import requests, math
API_BASE = "https://vessels-api.com/api/V1"
API_KEY = "YOUR_API_KEY"
def haversine_nm(lat1, lon1, lat2, lon2):
R_nm = 3440.065
phi1, phi2 = math.radians(lat1), math.radians(lat2)
dphi = math.radians(lat2 - lat1)
dlmb = math.radians(lon2 - lon1)
a = math.sin(dphi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(dlmb/2)**2
return 2*R_nm*math.asin(math.sqrt(a))
def minutes_to_arrival(lat_ship, lon_ship, lat_pilot, lon_pilot, speed_knots):
if not speed_knots or speed_knots <= 0:
return None
dist = haversine_nm(lat_ship, lon_ship, lat_pilot, lon_pilot)
hours = dist / speed_knots
return int(hours * 60)
# Example MMSI from the official sample:
params = {"mmsi": "258785000", "hours": 48}
r = requests.get(f"{API_BASE}/vessels/track", headers={"X-API-Key": API_KEY}, params=params)
r.raise_for_status()
data = r.json()["data"]
cp = data["current_position"]
lat, lon, spd = cp["latitude"], cp["longitude"], cp["speed_knots"]
# Replace with your port's pilot station coordinates:
pilot_lat, pilot_lon = 1.214, 103.86
eta_minutes = minutes_to_arrival(lat, lon, pilot_lat, pilot_lon, spd)
print(f"ETA to pilot station: {eta_minutes} minutes" if eta_minutes is not None else "Vessel not making way")
Tips:
- Use hours up to 168 to pull a week of history for compliance and utilization analysis.
- When include_predicted_eta is supported in your case, pass it to offload ETA computation to the API.
- Guard for null vessel.name; identifiers are reliable keys (imo/mmsi).
3) Expected arrivals and congestion signals for port ops
When your goal is to answer “is a car carrier near a port, and will it get a berth?”, combine expected arrivals with the live snapshot of congestion.
Expected arrivals: GET /port/expected-arrivals
Use a port identifier (e.g., ARBUE) to fetch declared/forecasted arrivals and their ETAs.
Example JSON (truncated):
You can correlate nearby vessels to these entries by mmsi/imo to flag “early arrival” or “off-schedule” states.
Congestion snapshot: GET /ports/congestion
This endpoint returns real-time anchorage/berth counts and recent wait-time statistics for the requested port.
Fields to watch:
- snapshot.vessels_in_anchorage — how many are stacking up outside
- snapshot.vessels_at_berth — indicator for berth availability pressure
- statistics.avg_wait_time_hours_last_7d — planning buffer for truck gates and pilots
- statistics.port_calls_count — volume context
Implementation pattern:
- Join expected arrivals with congestion to create a “risk of delay” badge next to each inbound car carrier.
- Use period=24h|3d|7d to calibrate your historical wait-time baseline.
4) Fleet context in one call with /vessels/fleet
If you track multiple car carriers (line-owned or chartered), the POST /vessels/fleet batch endpoint gives you positions and routes for many targets in a single request, plus a fleet-level summary.
POST body and cURL
Example JSON (truncated):
Add this to a dashboard card for “fleet at a glance,” where the ops team only needs a count of vessels at sea vs. in port and a short list of inbound ETAs.
5) ESG and regulatory view: IMO CII for car carriers
Automotive OEMs and carriers increasingly track carbon intensity. GET /vessels/green returns a CII score and rating (A–E) following IMO MEPC.339(76), plus distance and emissions estimates for the requested period.
cURL: 30-day CII snapshot
Example JSON (truncated):
Attach this to a shipment record to support scope and compliance reporting, or add a filter to your fleet view for “CII rating is A/B only.”
Putting it together: a minimal “car carrier near port” flow
- Resolve the port’s coordinates via GET /ports or GET /ports/data.
- Call GET /vessels/nearby with ship_type=Vehicles Carrier, and render by distance_nm ascending.
- When a user selects a vessel, call GET /vessels/track to show its marker, speed, and route context.
- Call GET /port/expected-arrivals for the port and correlate by mmsi/imo to show declared ETA vs. live proximity.
- Optionally enrich with GET /ports/congestion to warn if average wait time is elevated relative to last 7 days.
- If the user is a fleet operator, back the overview with POST /vessels/fleet for batch status and simple KPIs.
Engineering details that prevent edge-case bugs
- Authentication: pass X-API-Key on every request; there’s no OAuth flow. Handle 401 for invalid/missing keys.
- Errors: expect 400 for missing/invalid params, 404 for unknown vessel/port, 422 for out-of-range (e.g., radius>200), 429 for rate limits, 500 for server errors. Log envelope.status and envelope.message.
- Pagination: search endpoints return pagination metadata; nearby has limit. Keep per_page ≤ 100.
- Units: distances are nautical miles; speed is in knots; course/heading in degrees; timestamps are UTC.
- Nullability: vessel names may be null; prefer keys (imo/mmsi). predicted_eta can be null; so can route.distance_nm if unknown.
- Refresh cadence: AIS is near real-time; for dashboards, a 30–90s poll interval is typically adequate.
- Consistency: every response is {status, success, message, data}, so your client can centralize error handling.
Optional discovery: find the right car carrier asset
If you need to resolve a vessel by fuzzy name or to filter by tonnage/build year, use GET /vessels/search and pass query plus filters like ship_type=Vehicles Carrier. This is helpful when a port agent sends only the commercial name or a partial IMO.
Use the resulting imo/mmsi for subsequent /vessels/track and /vessels/nearby calls.
Security, environments, and ops
- Never ship YOUR_API_KEY in client-side code; route through a backend or serverless function.
- Implement exponential backoff on 429s; respect Retry-After if present.
- Feature flag the “ESG” and “Fleet” panels; you can progressively enhance the base nearby + track flow.
FAQ
Q: How do I filter only car carriers in the nearby endpoint?
A: Pass ship_type=Vehicles Carrier in GET /vessels/nearby. Combine with radius and limit for performance.
Q: What’s the difference between current_position.eta and route.eta?
A: current_position.eta comes from AIS broadcasts and may be null or stale. route.eta is derived from the voyage context; when available, it represents the predicted ETA to destination_port.
Q: Can I batch-check multiple mmsi values at once?
A: Yes. Use POST /vessels/fleet with a list of {imo, mmsi} objects. Include include_positions or include_routes flags as needed.
Q: Which timezone are port timestamps in?
A: All API timestamps are UTC. If you need local port time, read the port’s timezone from GET /ports or GET /ports/data and convert in your app.
Q: How often should I poll for a live map of inbound car carriers?
A: Start with a 30–60 second interval for /vessels/nearby and 60–120 seconds for /vessels/track. Cache results briefly and avoid overlapping requests.
Next steps
Stand up a “Car Carrier Near a Port” widget by combining /vessels/nearby and /vessels/track, then add /port/expected-arrivals and /ports/congestion for ops realism. Explore the full 18-endpoint surface in the Documentation, generate an API key via Register, and wire this into your platform. For advanced integrations and tooling, check out the MCP.