Bulk carrier operators and logistics teams need reliable, consistent AIS data to answer simple but critical questions: Where is my ship, when will it berth, what’s the route, who else is in the queue, and how do we track emissions? By the end of this guide you’ll integrate bulk carrier tracking into your transportation stack using vessels-api.com: searching for hulls, streaming live positions and voyage context, rolling up multiple ships into a fleet view, checking port congestion, and monitoring IMO CII readiness.
What makes this API practical for bulk carrier tracking
vessels-api.com exposes a focused REST surface for transportation use cases:
- 18 endpoints spanning vessel intelligence, fleet ops, port intelligence, and IMO CII scoring.
- One API key, one base URL, no OAuth. Send X-API-Key on every call.
- Consistent JSON envelope on every response: {"status","success","message","data"}.
- Near real-time AIS with up to 168 hours of historical positions per vessel.
- 7-day free trial and scale from a single developer to enterprise fleets.
This post goes deep on the endpoints most relevant to bulk carrier transportation:
- /vessels/search for finding bulkers by name, IMO, or MMSI with DWT filters.
- /vessels/track for live AIS position, route, ETA, and recent port calls.
- /vessels/fleet to hydrate a fleet dashboard in one request.
- /ports/congestion to understand queuing pressure and berth throughput.
- /vessels/green to monitor CII scoring for ESG and regulatory workflows.
Reference links you’ll use while building: Register, Documentation, MCP.
Authentication, base URL, and response envelope
All requests go to https://vessels-api.com/api/V1 and require the header X-API-Key: YOUR_API_KEY. Except for /vessels/fleet (POST), endpoints are GET. Every response shares the envelope {"status","success","message","data"} so you can centralize error handling and parsing.
- HTTP 200, 400, 401, 404, 422, 429, 500 are used for success and fault conditions.
- Timestamps are UTC ISO 8601 (e.g., 2026-04-27T21:35:36+00:00).
- Distances are nautical miles (nm); speeds are knots; coordinates are decimal degrees.
Track a bulk carrier: live AIS, route, and port visits
The core of a bulker ops view is a single endpoint that returns current AIS, position history (up to 168 hours), route, predicted ETA, and recent port calls. Use /vessels/track with either IMO or MMSI.
Official cURL for a documented track
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"
{
"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:10+00:00",
"age_minutes": 5132780,
"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
}
}
Key fields you’ll immediately use:
- data.vessel: Identifiers to bind this track to your TMS or voyage record.
- data.current_position: lat/lon, speed_knots, course_degrees, and timestamp_utc for map rendering and state estimation.
- data.route: departure/destination and average speed; available ETA when include_predicted_eta is enabled on other calls.
- data.last_port_visits: arrival/departure history for port call analytics and laytime checks.
Python example: extract a bulk carrier’s live state
The following Python snippet calls the same documented MMSI with a 48-hour window and prints a compact status line to feed your dashboard or alerting system.
import os
import requests
from datetime import datetime
API_KEY = os.getenv("VESSELS_API_KEY", "YOUR_API_KEY")
BASE_URL = "https://vessels-api.com/api/V1"
def track_bulk_carrier(mmsi: str, hours: int = 48):
url = f"{BASE_URL}/vessels/track"
params = {"mmsi": mmsi, "hours": hours}
headers = {"X-API-Key": API_KEY}
r = requests.get(url, headers=headers, params=params, timeout=20)
r.raise_for_status()
payload = r.json()
if not payload.get("success"):
raise RuntimeError(f"API error: {payload.get('message')}")
data = payload["data"]
vessel = data["vessel"]
pos = data["current_position"]
route = data.get("route") or {}
last_ports = data.get("last_port_visits") or []
lat = pos.get("latitude")
lon = pos.get("longitude")
spd = pos.get("speed_knots")
cog = pos.get("course_degrees")
ts = pos.get("timestamp_utc")
dep = route.get("departure_port")
dest = route.get("destination_port")
avg_spd = route.get("avg_speed_knots")
print(f"MMSI {vessel.get('mmsi')} | IMO {vessel.get('imo')} | "
f"Pos {lat},{lon} @ {ts} | SOG {spd} kn COG {cog}° | "
f"Voyage: {dep} → {dest} (avg {avg_spd} kn)")
if last_ports:
lp = last_ports[0]
print(f"Last port: {lp.get('port_name')} (arrival {lp.get('arrival_time')})")
if __name__ == "__main__":
track_bulk_carrier("258785000", hours=48)
Notes:
- Always check success and message for operational alerts in your logs.
- timestamps are UTC; convert to port local time zones only in the UI layer.
- position_history can be requested up to 168 hours for track lines and speed/turn analysis.
Find and filter bulk carriers
Start every flow by resolving identifiers. /vessels/search supports fuzzy name search and filtering by type, flag, dimensions, and capacity. For bulk carriers, deadweight_tonnage (DWT) brackets are particularly useful for routing suitability and terminal constraints.
Sample cURL that searches for “atlantic” and filters by flag (from the reference):
Tips for bulk carrier workflows:
- Use ship_type to isolate bulker classes when enriching your own vessel roster.
- Apply min_dwt/max_dwt to target Handy/Ultramax/Capesize operating ranges.
- Paginate with page and per_page (max 100). Store the pagination block for UI cursors.
Scale to a fleet view for operations
Fleet dispatchers need the status of dozens of bulkers at once. Instead of looping over single-vessel calls, use /vessels/fleet. It returns fleet rollups plus per-vessel position and route in a single POST.
Reference cURL (from the docs) batching an IMO and an MMSI:
Implementation notes for bulk carrier control towers:
- include_positions true hydrates maps without extra requests; add include_routes for voyage context.
- Use data.fleet.vessels_at_sea vs. vessels_in_port to drive alerting and KPIs.
- Normalize MMSI/IMO fields and de-duplicate vessels prior to POST to avoid double counting.
Manage terminal windows with port congestion
For bulk commodities like coal, grain, or iron ore, anchorage queues and berth time dominate schedule reliability. Use /ports/congestion with a UNLOCODE-style port_id to retrieve a real-time snapshot and rolling wait-time statistics.
Reference cURL (from the docs) for Buenos Aires, ARBUE:
You’ll use these fields to power dashboards and exception monitoring:
- data.snapshot.vessels_in_anchorage and vessels_at_berth for daily operations meetings.
- data.statistics.avg_wait_time_hours_last_7d and max_wait_time_hours_last_7d for schedule risk assessment.
- data.statistics.port_calls_count for trend normalization (how busy the port has been).
Complement congestion with /port/expected-arrivals to anticipate terminal traffic, and /ports/data for live vessel counts to back your arrival plans.
- Expected arrivals cURL (from the docs):
ESG and compliance for bulk carriers with IMO CII
Bulk carriers are under scrutiny for carbon intensity. /vessels/green returns distance sailed, estimated CO2, and CII rating (A to E) for a selectable period. Use this to gate fixtures, plan slow steaming, or report to stakeholders.
Reference cURL (from the docs) using MMSI with a 30-day period:
Fields to integrate:
- data.estimated_emissions.co2_tons and co2_per_nm to visualize intensity by leg.
- data.cii.score and data.cii.rating to enforce charter policies.
- data.period for filter labels in dashboards and PDF exports.
Nearby vessels for situational awareness
When coordinating pilotage or tug windows for bulkers, a quick proximity scan around a pilot boarding place helps. /vessels/nearby returns vessels within a radius in nautical miles, with optional filters by ship_type and limit.
Reference cURL (from the docs) with a 30 nm radius:
Use data.vessels[i].distance_nm, speed_knots, and navigational_status to sort by relevance when sequencing bulk carrier approaches.
Design tips for a reliable bulk carrier tracking service
- Cache by vessel key (IMO or MMSI) with a short TTL to reduce repeated calls on high-traffic dashboards. The track endpoint’s freshness varies by AIS update cadence; tune TTL based on your operational needs.
- Normalize UTC timestamps at ingestion, convert at render time using the destination port’s timezone from /ports or /ports/data.
- Backfill voyage arcs using position_history (up to 168 hours) to draw polylines and compute segment averages.
- Show last_port_visits context near the map to anchor the story of the current voyage (laytime, shifting, or port stay anomalies).
- Handle error codes centrally—401 for missing/invalid API key, 404 when a vessel is not in the catalog, 422 for parameter ranges (e.g., hours > 168).
Putting it together: a minimal bulk carrier ops flow
1) Resolve the ship
Use /vessels/search to turn a charter name into a canonical MMSI/IMO, optionally filtered by flag or DWT. Store {imo, mmsi, name, vessel_type} in your voyage record.
2) Hydrate the live card
Call /vessels/track with hours=24..168. Render:
- Position pin from current_position.latitude/longitude
- SOG/COG and navigational_status as status chips
- Track line from position_history
- Voyage header from route and predicted_eta (when included and present)
- Last port visit for operational history
3) Roll up a fleet
For dispatch: batch the day’s bulkers via /vessels/fleet and sort by vessels_at_sea, ETA confidence, or distance to pilot station.
4) Check the terminal picture
Query /ports/congestion for the discharge/load port to anticipate anchorage time and berth availability. Supplement with /port/expected-arrivals to see who is inbound.
5) Monitor emissions
Pull /vessels/green nightly to monitor the CII trajectory of your bulkers. Flag D/E ratings for operational action or chartering limits.
Operational details that save you time
- Pagination: /vessels/search returns a pagination block with current_page, per_page, total, and last_page. Always read last_page to stop paginated fetches.
- Units: All speeds in knots, distances in nautical miles. Do not mix with km/h or km in analytics.
- Identifier hygiene: Prefer IMO as a stable key for asset-level joins; MMSI can change with reflagging or equipment swaps.
- Rate limiting: If you see 429 Rate limit exceeded, back off with jitter and retry; centralize key usage across services.
- Legacy endpoints: /vessel/* remain available but prefer the richer /vessels/* surface for bulk carrier applications that need route, history, and analytics.
Extended examples you can copy
Batch hydrate a bulker fleet (JavaScript, fetch)
const API_KEY = "YOUR_API_KEY";
const BASE_URL = "https://vessels-api.com/api/V1";
async function loadFleet(vessels) {
const res = await fetch(`${BASE_URL}/vessels/fleet`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
vessels, // e.g., [{ imo: "9122556" }, { mmsi: "309374000" }]
include_positions: true,
include_routes: true
})
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const payload = await res.json();
if (!payload.success) throw new Error(payload.message);
const { fleet, vessels: items } = payload.data;
console.log(`Fleet: total=${fleet.total_vessels} sea=${fleet.vessels_at_sea} port=${fleet.vessels_in_port}`);
// Map-ready markers:
return items.map(v => ({
key: v.imo || v.mmsi,
name: v.name,
lat: v.position?.latitude,
lon: v.position?.longitude,
sog: v.position?.speed_knots,
dest: v.route?.destination_port
}));
}
loadFleet([{ imo: "9122556" }, { mmsi: "309374000" }])
.then(markers => console.log(markers))
.catch(err => console.error(err));
Compute a simple “ETA risk” signal for a bulker
Combine /vessels/track with /ports/congestion for the destination port:
- If route.eta is null and congestion snapshot shows high vessels_in_anchorage, flag “ETA Uncertain.”
- If avg_wait_time_hours_last_7d is rising week-over-week, increase buffer on truck or rail windows.
- Show last_port_visits to contextualize whether delays are upstream or terminal-driven.
FAQ
What identifiers should I store for a bulk carrier?
Store both IMO and MMSI when available. Use IMO for long-term joins; use MMSI to query live AIS. The API returns both under data.vessel.
How fresh is the “live” track data?
Positions are based on AIS updates and may vary by coverage and transmission interval. The current_position.timestamp_utc and age_minutes fields indicate recency; you can surface a “stale” badge when age exceeds your tolerance.
How far back can I get position history?
/vessels/track supports hours up to 168 (7 days). Use the hours parameter to control payload size and the polyline length on maps.
Can I filter for bulk carriers only?
Yes. Use /vessels/search with ship_type and DWT filters (min_dwt/max_dwt). Combine with pagination fields to iterate large result sets.
How do I handle time zones for ETAs and port operations?
All timestamps are UTC. Use /ports or /ports/data to retrieve timezone metadata per port and convert at render time. Keep calculations in UTC to avoid daylight-saving pitfalls.
Build your bulk carrier tracking, fleet operations, and port coordination features today with vessels-api.com. Start with the track endpoint, then scale out to fleet, ports, and CII as your use case grows. Explore the Documentation, experiment in the MCP, and Register to get your API key and ship your integration.



