API to Track a Container Ship

API to Track a Container Ship

You need to track a container ship reliably: get its latest AIS position, 24–168 hours of history, current route and ETA, and connect that to your transportation workflows. By the end of this post, you’ll be able to search for a boxship by MMSI/IMO or fuzzy name, stream its live track, compute voyage analytics on demand, and scale to a fleet view—all via vessels-api.com with a single API key and a consistent JSON schema.

Why developers track container ships with vessels-api.com

Vessels API is a transportation-focused REST API offering 18 endpoints across vessel search, live AIS tracking, fleet operations, port intelligence, IMO CII emissions scoring, and a premium real-time AIS feed. It’s designed for developers building logistics visibility, ETA predictions, and fleet dashboards for container shipping.

Illustration: API to Track a Container Ship
  • Single base URL: https://vessels-api.com/api/V1 and a single header for auth (X-API-Key).
  • Consistent JSON envelope on every response: {status, success, message, data}.
  • Global AIS coverage with near real-time refresh rates for live tracking.
  • 7-day free trial on all plans; scalable from indie projects to enterprise fleets.

Reference: Documentation • MCP • Register

Core endpoints for tracking a container ship

For container shipping, these endpoints cover the happy path from discovery to live tracking to analytics and operations:

  • GET /vessels/search — find your vessel by fuzzy name, IMO, or MMSI.
  • GET /vessels/track — live position, up to 168h history, route, and predicted ETA.
  • GET /vessels/analytics — on-demand voyage statistics for a single ship or fleet.
  • POST /vessels/fleet — batch positions and routes in one call for multiple ships.
  • GET /port/expected-arrivals — inbound calls with ETA and last port (optional complement to your ETA logic).

Authenticate once, keep the headers simple

Every request uses the same base URL and the same auth header:

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

There’s no OAuth flow and no per-endpoint auth differences to manage. All timestamps are UTC in ISO 8601 format, distances are nautical miles (nm), and speeds are in knots.

1) Find the container ship: GET /vessels/search

Start by resolving a vessel’s identifiers. Search supports fuzzy name queries and filters that matter to container shipping (TEU range, ship_type, flag, build year):

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

Key request details:

  • query: vessel name (supports fuzzy matching), or direct IMO/MMSI.
  • Optional filters: ship_type, min_teu/max_teu, min_dwt/max_dwt, year_built_from/year_built_to.
  • Pagination: page and per_page (max 100).

Response highlights (in data.vessels[]): imo, mmsi, name, flag, vessel_type, gross_tonnage, deadweight_tonnage, year_built, length_m, width_m. Use these to decide if you’ve got the correct boxship and to display basics on your UI card.

2) Live track with history and route: GET /vessels/track

Once you have the MMSI or IMO, pull the live AIS track. This endpoint returns the current fix, optional up to 168 hours of position history, current route, predicted ETA, and recent port calls.

Official cURL and JSON (container ship track)

Copy and run this as-is (replace YOUR_API_KEY):

Official JSON response:

{
"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:45+00:00",
"age_minutes": 5117600,
"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
}
}

What you’ll actually use in a container-shipping workflow:

  • data.current_position.latitude/longitude: plot the live fix on your map.
  • data.current_position.speed_knots and course_degrees: determine if underway and direction of travel.
  • data.route.destination_port and eta: display voyage leg target and ETA on your shipment tracking card.
  • data.last_port_visits[]: feed recent port calls into lead-time and dwell analyses.

Tips:

  • Use hours parameter to control history depth (default 24, max 168). Container ETDs/ETAs often need at least 48–72 hours of context.
  • Pass include_route=true, include_predicted_eta=true, include_weather=true when you need the additional context; omit for a lighter payload.
  • All timestamps are UTC; convert to local timezones at the UI edge only.

Python example: fetch track and render a map marker + ETA

import requests
from datetime import datetime

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://vessels-api.com/api/V1"

def get_track(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() # {status, success, message, data}
if not payload.get("success"):
raise RuntimeError(payload.get("message", "API error"))
return payload["data"]

def summarize_track(data: dict):
vessel = data.get("vessel", {})
pos = data.get("current_position", {})
route = data.get("route", {})

lat = pos.get("latitude")
lon = pos.get("longitude")
speed = pos.get("speed_knots")
ts = pos.get("timestamp_utc")
eta = route.get("eta") or pos.get("eta")
dest = route.get("destination_port") or pos.get("destination")

return {
"mmsi": vessel.get("mmsi"),
"imo": vessel.get("imo"),
"coordinates": (lat, lon),
"speed_knots": speed,
"timestamp_utc": ts,
"destination": dest,
"eta_utc": eta
}

if __name__ == "__main__":
data = get_track("258785000", hours=48)
summary = summarize_track(data)
print("MMSI:", summary["mmsi"])
print("IMO:", summary["imo"])
print("Coords:", summary["coordinates"])
print("Speed (kn):", summary["speed_knots"])
print("Timestamp (UTC):", summary["timestamp_utc"])
print("Destination:", summary["destination"])
print("ETA (UTC):", summary["eta_utc"])

This pattern keeps your integration aligned with the response envelope and works well in services where you cache the latest position for a short TTL (e.g., 1–5 minutes) to reduce repeated calls when rendering many containers on a map.

3) Voyage analytics for a container ship: GET /vessels/analytics

Pull on-demand voyage statistics for a single vessel to enrich ETAs, performance dashboards, and exception management. Set type=vessel and provide mmsi or imo.

Key fields to use from data.statistics:

  • total_distance_nm: useful to normalize fuel estimates or compare service strings.
  • avg_speed_knots and max_speed_knots: confirm schedule adherence or detect slow steaming.
  • port_calls_count and total_time_in_port_hours: monitor dwell and terminal efficiency.
  • ports_visited: feed your lead-time models when correlating origin/destination pairs.

Periods accepted: 24h, 7d, 30d, 90d. Choose 7d for weekly reporting on specific port calls or legs, 30d for schedule adherence trends.

4) Fleet operations at scale: POST /vessels/fleet

When you track multiple container ships (e.g., all active legs on a loop or your NVOCC coverage), batch positions and routes in one request to reduce network overhead and render a unified dashboard.

What you get back:

  • data.fleet: aggregate counts (total_vessels, vessels_at_sea, vessels_in_port).
  • data.vessels[]: an array of vessels with imo, mmsi, name, position, and route.

For container shipping, render vessel cards in a list or map clusters, compute exception badges for “off-schedule” (e.g., no movement in X hours, missing AIS), and sort by ETA to next port.

5) Port intelligence add-on: GET /port/expected-arrivals

To augment your ETA and berth planning logic, query expected arrivals for a destination port. This is particularly useful for container terminals with volatile congestion.

Key data fields include expected_arrivals[] with mmsi, imo, name, vessel_type, eta, and departure_port. Combine this with the live /vessels/track ETA to cross-check inbound flows for your ship or competing vessels queued for the same terminal window.

Field guide: parameters, units, timestamps, pagination

  • Authentication: X-API-Key header is required for all endpoints; use YOUR_API_KEY in examples.
  • Units: distances in nautical miles (nm); speeds in knots; coordinates in decimal degrees.
  • Timestamps: ISO 8601 strings in UTC (e.g., 2026-04-27T21:35:36+00:00). Convert for local display; keep UTC for storage and analytics.
  • Pagination: where applicable (e.g., /vessels/search), use page and per_page (max 100). Use the pagination object in the response to implement “Load more.”
  • History windows: /vessels/track supports hours up to 168 (7 days). Choose the smallest window you need to balance payload size and context.
  • Error handling: check the top-level {status, success, message}. Status 401 indicates invalid/missing API key. 404 indicates vessel/port not found. 422 indicates parameter out of range. 429 indicates rate limit exceeded. Implement retries/backoff for 429/500 only.

Putting it together: typical container shipping workflows

Shipment visibility: one vessel, one leg

  • Resolve target vessel with /vessels/search using name or direct MMSI/IMO.
  • Use /vessels/track with hours=48 and include_route=true to get the current fix, history, and voyage leg details.
  • Render a map marker with speed_knots and course_degrees; display route.destination_port and route.eta on the card.
  • Set a short cache (1–5 minutes) to avoid flicker and reduce calls while the ship is at sea.

Fleet dashboard: entire service loop

  • Call /vessels/fleet with a list of MMSIs/IMOs, include_positions=true, include_routes=true.
  • Aggregate vessels_at_sea vs. vessels_in_port to compute operational KPIs.
  • Sort by next ETA; flag vessels with speed=0 and navigational_status indicating at anchor for > X hours.

ETA confidence and port planning

  • Cross-reference /vessels/track route.eta with /port/expected-arrivals for the destination terminal.
  • Use /vessels/analytics (type=vessel) over 7d to spot slow steaming and adjust ETA buffers.

Compliance and ESG for container ships

For teams tracking emissions exposure, use GET /vessels/green to pull IMO CII scoring, estimated CO2 tons, and rating (A–E) over a period like 30d or 1y. While not required to track position, pairing emissions and voyage data helps you create compliance-aware routing and carrier-scorecards for container services.

Use data.cii.rating to highlight risk (D/E) and data.estimated_emissions.co2_per_nm to normalize across legs.

Operational reliability notes

  • Data envelope consistency: every response has {status, success, message, data}, so your error handling can be uniform across endpoints.
  • AIS coverage and refresh: integrate at the cadence your UI needs; implement server-side caches keyed by MMSI/IMO with short TTLs.
  • Null-safe UI: route.distance_nm or vessel name can be null. Always guard against null when rendering labels and metrics.
  • History vs. payload size: hours=168 can be large. For mobile or map-heavy UIs, reduce hours to 12–24 for smooth panning/zooming.

JavaScript quickstart (optional alternative to Python)

async function fetchTrack(mmsi, hours = 48) {
const url = new URL("https://vessels-api.com/api/V1/vessels/track");
url.searchParams.set("mmsi", mmsi);
url.searchParams.set("hours", String(hours));

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(); // {status, success, message, data}
if (!payload.success) {
throw new Error(payload.message || "API error");
}
const { vessel, current_position, route } = payload.data;
return {
mmsi: vessel?.mmsi || null,
imo: vessel?.imo || null,
lat: current_position?.latitude ?? null,
lon: current_position?.longitude ?? null,
speed_knots: current_position?.speed_knots ?? null,
eta_utc: (route && route.eta) || current_position?.eta || null,
dest: (route && route.destination_port) || current_position?.destination || null
};
}

// Example usage:
fetchTrack("258785000", 48)
.then(summary => console.log(summary))
.catch(err => console.error(err));

Troubleshooting and best practices

  • Vessel not found (404): Try searching by IMO or fuzzy name with /vessels/search. Confirm you’re using the correct MMSI/IMO.
  • Sparse history or null route: Increase hours to 48–72; include_route=true. AIS gaps happen; your UI should degrade gracefully.
  • Rate limit (429): Implement exponential backoff and short-lived caching per vessel.
  • Port identifiers: For port endpoints, use the documented identifiers (e.g., ARBUE). Keep ETAs in UTC to avoid DST complications.

FAQ

How often should I poll /vessels/track for a single container ship?
Most teams poll every 1–5 minutes while underway and back off to 15–30 minutes when speed_knots=0 or the vessel is in port. Cache the last good response to avoid UI flicker.

Can I request only the current position without history?
Yes. Omit the hours parameter or set a small window. You can also omit include_route/include_predicted_eta/include_weather to keep the payload minimal.

What identifier should I use—MMSI or IMO?
Use whichever you have. MMSI is common for tracking; IMO is persistent across flag changes. /vessels/search can translate between them.

How do I batch multiple container ships efficiently?
Use POST /vessels/fleet with include_positions and include_routes as needed. It returns aggregate fleet counts and a per-vessel array in one response.

How do I get upcoming arrivals for a port my container ship is heading to?
Call GET /port/expected-arrivals with the port identifier to list inbound ships with ETA and origin. Combine with your vessel’s /vessels/track ETA to assess berth competition.

Next steps

Build your container-ship visibility now: search by name or MMSI, get a live fix and voyage route, and scale to a fleet view in a few requests. Start with the official examples above, then explore the full surface area in the Documentation. When you’re ready, get your key and ship your integration: Register. For local-first or agent-style development, check the MCP tools.

Ready to get started?

Get your API key and start tracking vessels in minutes.

Get API Key

Related posts