Heavy Lift Vessel Near a Port

Heavy Lift Vessel Near a Port

You need to know, right now, if a heavy-lift vessel is approaching or holding near your port—and you want to turn that into a reliable ETA, berth plan, and compliance snapshot without stitching together multiple data sources. By the end of this post, you’ll: query heavy-lift vessels near a port, drill into a specific ship’s live track and recent port calls, check expected arrivals for terminal planning, and pull an at-a-glance CII rating to brief your ESG team—using a single REST API with one key and one JSON shape.

Why heavy-lift near a port is different (and how to build it once)

Heavy-lift vessels don’t behave like typical container or bulk carriers. They slow steam for delicate cargo, anchor to await tide or pilots, and may perform ship-to-shore crane ops that alter port timelines. Your app needs three things in a single flow:

Illustration: Heavy Lift Vessel Near a Port
  • Is there a heavy-lift unit inside a 10–50 NM radius of the port?
  • What is its live position, movement vector, and last port history?
  • How does that translate into terminal readiness, congestion risk, and ESG reporting?

With vessels-api.com, you hit one base URL (https://vessels-api.com/api/V1), use one header (X-API-Key), and get a consistent JSON envelope: {status, success, message, data}. Below, we’ll stitch four endpoints into a production-ready workflow tailored to heavy-lift near ports:

  • GET /vessels/nearby — discover heavy-lift vessels inside a port radius.
  • GET /vessels/track — confirm identity, live vector, and recent calls.
  • GET /port/expected-arrivals — see who’s inbound with ETA and origin.
  • GET /vessels/green — retrieve IMO CII context for compliance dashboards.

Endpoint 1: Find a heavy-lift vessel within a port radius

When operations asks “do we have a heavy-lifter off the breakwater?”, you answer with a radius query centered on your port’s lat/lon. The /vessels/nearby endpoint returns all vessels in a circle with optional ship type filtering and limit control.

HTTP request

GET /vessels/nearby?latitude={lat}&longitude={lon}&radius={nm}&ship_type={type}&limit={n}
Header: X-API-Key: YOUR_API_KEY
Base: https://vessels-api.com/api/V1

Parameters that matter:

  • latitude, longitude — decimal degrees for the port center.
  • radius — nautical miles; default 50, max 200.
  • ship_type — optional text filter. Use the classification your workflow uses for heavy-lift (e.g., “Heavy Lift”).
  • limit — optional; default 50.

Example cURL

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

How to use the data:

  • data.center — confirms the query center and parameters you used.
  • data.vessels[] — each item contains {imo, mmsi, name, ship_type, position{latitude, longitude, timestamp_utc}, distance_nm, speed_knots, course_degrees, navigational_status}.

Immediate ops logic:

  • If speed_knots ≈ 0 and distance_nm < 3, your heavy-lift is likely anchored or alongside—trigger pilot/tug checks.
  • If course_degrees points toward the channel and speed increases, escalate to berth readiness and crane allocation.

JavaScript example (Node.js, native fetch)

import fetch from "node-fetch";

const API_KEY = process.env.VESSELS_API_KEY; // set YOUR_API_KEY in env for local dev
const baseUrl = "https://vessels-api.com/api/V1";

async function findHeavyLiftNearPort(lat, lon, radiusNm = 25) {
const url = new URL(`${baseUrl}/vessels/nearby`);
url.searchParams.set("latitude", lat);
url.searchParams.set("longitude", lon);
url.searchParams.set("radius", radiusNm);
url.searchParams.set("ship_type", "Heavy Lift");
url.searchParams.set("limit", "25");

const res = await fetch(url.toString(), {
headers: { "X-API-Key": API_KEY }
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();

// Consistent envelope: {status, success, message, data}
if (!json.success) throw new Error(json.message || "API error");

const vessels = json.data?.vessels ?? [];
// Pick the closest heavy-lift candidate
vessels.sort((a, b) => (a.distance_nm ?? Infinity) - (b.distance_nm ?? Infinity));
const top = vessels[0];

if (!top) return null;

return {
mmsi: top.mmsi,
imo: top.imo,
name: top.name,
distanceNm: top.distance_nm,
speedKts: top.speed_knots,
courseDeg: top.course_degrees,
status: top.navigational_status,
lastUpdate: top.position?.timestamp_utc
};
}

// Example usage:
// findHeavyLiftNearPort(1.265, 103.833).then(console.log).catch(console.error);

Tip: The timestamp_utc fields are ISO 8601 in UTC (e.g., 2026-05-01T12:30:00+00:00). Cache radius lookups briefly (e.g., 30–60 seconds) for UI lists; fetch on demand for detail panes.

Endpoint 2: Confirm identity and movement with live track

Once you have a candidate heavy-lift vessel, confirm its vector and recent port calls with the tracking endpoint. You’ll also get route metadata and optional weather when included.

Official live sample (copy/paste)

The following call and JSON are the official, documented track fixture for MMSI 258785000 with 48 hours of history. Use this as a reference for the JSON envelope and field names.

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

Fields you’ll actually wire into your heavy-lift UI:

  • data.vessel.imo, data.vessel.mmsi — primary identifiers for routing and ESG joins.
  • data.current_position.latitude, longitude — present the exact map pin. Coordinates are decimal degrees.
  • data.current_position.speed_knots, course_degrees, navigational_status — drive your “Arriving / At Anchor / Berthed” badges.
  • data.current_position.timestamp_utc — stale data guardrail; if older than your UI SLO, flag it.
  • data.route.{departure_port, destination_port, avg_speed_knots} — contextualize voyage assumptions.
  • data.last_port_visits[] — show most recent port calls to operations.

Python example (requests)

import os
import requests
from datetime import datetime, timezone

API_KEY = os.environ.get("VESSELS_API_KEY")
BASE = "https://vessels-api.com/api/V1"

def get_track_by_mmsi(mmsi: str, hours: int = 24):
url = f"{BASE}/vessels/track"
params = {"mmsi": mmsi, "hours": str(hours)}
headers = {"X-API-Key": API_KEY}
r = requests.get(url, params=params, headers=headers, timeout=15)
r.raise_for_status()
payload = r.json()
if not payload.get("success"):
raise RuntimeError(payload.get("message", "API error"))
return payload["data"]

def summarize_heavy_lift(track):
cp = track.get("current_position") or {}
vessel = track.get("vessel") or {}
last_ts = cp.get("timestamp_utc")
last_dt = None
if last_ts:
last_dt = datetime.fromisoformat(last_ts.replace("Z", "+00:00")).astimezone(timezone.utc)

return {
"imo": vessel.get("imo"),
"mmsi": vessel.get("mmsi"),
"lat": cp.get("latitude"),
"lon": cp.get("longitude"),
"speed_knots": cp.get("speed_knots"),
"course_degrees": cp.get("course_degrees"),
"navigational_status": cp.get("navigational_status"),
"last_update_utc": last_dt.isoformat() if last_dt else None,
"destination": cp.get("destination"),
"eta": cp.get("eta"),
"recent_ports": [p.get("port_name") for p in (track.get("last_port_visits") or [])]
}

# Example:
# data = get_track_by_mmsi("258785000", hours=48)
# print(summarize_heavy_lift(data))

Developer note: hours supports up to 168 (7 days). For map trails, request hours=6–24 and plot position_history (if present). For dashboards, you can omit include_route/include_weather to minimize payload unless you explicitly need them.

Endpoint 3: Cross-check port plans with expected arrivals

Terminal planners need a single stream of “who is inbound” with ETAs and origin ports. The /port/expected-arrivals endpoint provides that list for a specific port code.

HTTP request

GET /port/expected-arrivals?port={PORT_ID}
Header: X-API-Key: YOUR_API_KEY
Base: https://vessels-api.com/api/V1

Response includes:

  • data.expected_arrivals[] — each with {mmsi, imo, name, vessel_type, eta, departure_port}.
  • data.port_id, data.port_name — identifiers for routing and display.

Example cURL

How to apply this to heavy-lift near port:

  • Filter arrivals by vessel_type matching your heavy-lift taxonomy.
  • Join with /vessels/track on mmsi to reconcile live position vs. ETA variance.
  • Surface “terminal risk” when ETA ± live track distance/time drift beyond your threshold.

Endpoint 4: Attach CII emissions context for ESG dashboards

Heavy-lift voyages can be atypical in speed profiles and ballast vs. laden legs. The /vessels/green endpoint provides a compact CII summary for regulatory and internal KPI blending.

HTTP request

GET /vessels/green?imo={imo}&period={24h|7d|30d|1y}
GET /vessels/green?mmsi={mmsi}&period={24h|7d|30d|1y}
Header: X-API-Key: YOUR_API_KEY
Base: https://vessels-api.com/api/V1

Response highlights:

  • data.estimated_emissions.{co2_tons, co2_per_nm} — tonnage and intensity.
  • data.cii.{score, rating, year, regulation_reference} — A to E rating (A best).
  • data.period — align your UI filters with period for clarity.

Example cURL

Practical pairing: show the CII rating adjacent to the arrival card. Your ops team can nudge tug or berth allocations without losing sight of emissions intensity trends tied to special cargo moves.

Workflow: Heavy-lift near a port, end-to-end

  1. Discover presence. Call /vessels/nearby around the port’s lat/lon with a 10–50 NM radius and ship_type filter to identify heavy-lift candidates. Sort by distance_nm.
  2. Confirm track. For the top candidate, call /vessels/track with mmsi to pull current_position and last_port_visits. Validate staleness with timestamp_utc and age_minutes.
  3. Check arrivals. Pull /port/expected-arrivals for the same port to list declared inbound vessels and ETAs. Reconcile with live groundspeed and distance to identify drift.
  4. Add ESG. Request /vessels/green on the same vessel (mmsi or imo) to render a CII badge and CO2 intensity next to the ops data.
  5. Alert logic. If course_degrees aligns with the approach lane and speed_knots increases while distance_nm decreases under a threshold, escalate terminal readiness via your alert system.

Operations details that save time

  • Authentication: Send X-API-Key: YOUR_API_KEY on every request. There is no OAuth dance or per-endpoint override.
  • Base URL: https://vessels-api.com/api/V1. All endpoints discussed here are GET, except /vessels/fleet which is POST for batch workflows.
  • JSON envelope: Always expect {status, success, message, data}. Check success before dereferencing payloads.
  • Units: Distances are nautical miles (nm). Speeds are knots. Coordinates are decimal degrees. Time is UTC in ISO 8601 strings.
  • Refresh cadence: AIS-derived positions refresh near real-time; use UI caching for lists (e.g., 30–60s) and fetch on focus for detail panels.
  • Pagination: /vessels/search supports page/per_page. For nearby and arrivals, use limit or client-side truncation where applicable.
  • Error handling: 401 means the key is missing/invalid; 422 indicates parameter out of range (e.g., radius > max). Back off on 429 rate limit responses.

Bonus: Fleet view for project cargo programs

If your heavy-lift ops span multiple vessels and ports, consolidate data with a single POST to /vessels/fleet. Include both positions and routes for a clean, low-latency dashboard card list. Example body (JSON): {"vessels":[{"imo":"9122556"},{"mmsi":"258785000"}], "include_positions":true}. This returns batch details with fleet rollups such as vessels_at_sea and vessels_in_port. Ideal for multi-jurisdictional infrastructure moves where two or three heavy-lifters converge on different terminals.

Port context: congestion and live counts (when you need it)

To contextualize a heavy-lift approach with what’s happening inside the breakwater, leverage:

  • /ports/data — live vessel counts at a port, general info (timezone matters for ops boards).
  • /ports/congestion — snapshot of anchorage vs. berth counts plus wait-time statistics for a specified time window.

Use these to temper your ETA commitments: if congestion shows elevated anchorage counts or long averages, add buffer to pilot/tug scheduling. When consuming congestion data, align your UI labels with the period parameter (e.g., last 7d).

Cut-and-paste snippets you’ll reuse

Minimal cURL for a quick check (discover, then track)

# 1) Discover heavy-lift near a port center
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/nearby?latitude=37.94&longitude=23.62&radius=20&ship_type=Heavy%20Lift&limit=10"

# 2) Confirm live vector on a chosen MMSI
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"

Compact Node.js function for arrival drift

import fetch from "node-fetch";

const API = "https://vessels-api.com/api/V1";
const KEY = process.env.VESSELS_API_KEY;

async function expectedArrivals(port) {
const res = await fetch(`${API}/port/expected-arrivals?port=${encodeURIComponent(port)}`, {
headers: { "X-API-Key": KEY }
});
const j = await res.json();
if (!j.success) throw new Error(j.message || "API error");
return j.data.expected_arrivals || [];
}

async function currentTrack(mmsi, hours = 24) {
const url = `${API}/vessels/track?mmsi=${encodeURIComponent(mmsi)}&hours=${hours}`;
const res = await fetch(url, { headers: { "X-API-Key": KEY } });
const j = await res.json();
if (!j.success) throw new Error(j.message || "API error");
return j.data;
}

// Compare ETA list with live groundspeed, naive drift detector
export async function arrivalDriftReport(port) {
const arrivals = await expectedArrivals(port);
const heavyLift = arrivals.filter(a => (a.vessel_type || "").toLowerCase().includes("heavy"));
const out = [];
for (const a of heavyLift) {
const t = await currentTrack(a.mmsi, 12);
const pos = t.current_position || {};
out.push({
mmsi: a.mmsi,
name: a.name,
declaredEta: a.eta,
speedKts: pos.speed_knots,
lastFix: pos.timestamp_utc
// In real code, estimate distance/time-to-go using pos and route/destination if present.
});
}
return out;
}

What sets this integration up for fast shipping

  • Single header, single base URL — no special-casing auth code per endpoint.
  • Consistent envelope — treat {status, success, message, data} as a contract; your error handlers can be generic.
  • Global AIS coverage and near real-time refresh — one code path works across regions and port states.
  • Trial-friendly — spin a prototype for ops in under a day, then scale it to a full fleet board with /vessels/fleet.

FAQ

Q: How often should I poll for “nearby” when rendering a port map?
A: For list views and map clusters, 30–60 seconds is a good baseline. For a selected vessel detail pane, fetch on focus or every 10–20 seconds if you need near-live movement. Always respect rate limits and use conditional UI refresh where possible.

Q: What’s the difference between course_degrees and heading_degrees?
A: course_degrees is the actual course over ground (COG). heading_degrees is the vessel’s bow orientation. In tight maneuvering near a port, heading and course may diverge due to currents or turning maneuvers.

Q: How do I filter only heavy-lift vessels?
A: Use the ship_type filter with /vessels/nearby or inspect vessel_type/name fields from search/track results. Keep your taxonomy consistent—e.g., “Heavy Lift” or your chosen label—and filter case-insensitively on the client if needed.

Q: Can I get both positions and route for multiple heavy-lift vessels at once?
A: Yes. Use POST /vessels/fleet with a list of {imo, mmsi} objects and include_positions/include_routes set to true. This reduces round-trips and helps keep dashboards responsive.

Q: What does navigational_status represent?
A: It’s an AIS-derived numeric code. Common states include underway, at anchor, and moored. Use it to drive UI badges and to distinguish “nearby and moving” from “nearby and anchored.”

Start building the heavy-lift near-port workflow

Use the discovery, tracking, arrivals, and CII endpoints outlined here to stand up a focused heavy-lift view for your port ops or project cargo team. The endpoints share one base URL and one header, so you can ship quickly and iterate safely. Get a key, read the specs, and experiment interactively with the MCP tools:

With these four endpoints, your UI can answer the only question that matters on a busy pier: is the heavy-lifter close, what’s its vector, when will it hit the berth, and are we compliant?

Ready to get started?

Get your API key and start tracking vessels in minutes.

Get API Key