Salvage coordinators and emergency response teams need reliable maritime situational awareness: where a distressed vessel is right now, which assets are close enough to assist, how long congestion may delay port entry, and whether your fleet of tugs and salvage ships is moving efficiently. By the end of this guide you will query real-time AIS positions, find nearby vessels within a radius, batch-track an entire response fleet, and monitor port congestion using the vessels-api.com REST endpoints.
Why salvage operations benefit from a focused maritime tracking API
Salvage incidents compress time. You have minutes to identify the distressed ship’s last reliable coordinates, vector available assets, and agree on a safe port of refuge. The Vessels API provides:
- 18 REST endpoints for vessel search, live tracking, fleet operations, port intelligence, and IMO CII scoring
- One API key, one base URL — X-API-Key header, no OAuth
- Consistent JSON patterns so you can parse responses uniformly
- Global AIS coverage with near real-time refresh rates
- A 7-day free trial and a platform that scales from an indie tool to enterprise operations
In this post, we’ll go deep on four endpoints that matter most to salvage workflows:
- GET /vessels/track — live position, short-term track history, route, predicted ETA, and weather
- GET /vessels/nearby — find assist-capable assets within a radius of an incident
- POST /vessels/fleet — batch positions and routes for your response fleet
- GET /ports/congestion — quantify congestion and likely wait times at destination ports
Endpoint 1: Live AIS tracking with route and ETA
When a casualty is reported, the first query you run should return the latest AIS fix, speed, course, nav status, and, if available, the intended destination and ETA. Use GET /vessels/track.
When to use it
- Locate distressed vessels by IMO or MMSI
- Get last 24–168 hours of track history to validate drift and last reliable vectors
- Pull predicted ETA and route for incident planning
- Overlay weather details when relevant to your dashboard
HTTP request
Base URL: https://vessels-api.com/api/V1
Auth: X-API-Key header
Required parameter: one of imo or mmsi
Practical options for salvage:
- hours=24..168 (default 24) — capture position history
- include_route=true — show departure/destination context
- include_predicted_eta=true — evaluate timelines
- include_weather=true — enrich your UI if needed
cURL example (copy-pasteable):
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48&include_route=true&include_predicted_eta=true&include_weather=true"
JavaScript fetch example
async function trackVessel(mmsi) {
const url = new URL("https://vessels-api.com/api/V1/vessels/track");
url.searchParams.set("mmsi", mmsi);
url.searchParams.set("hours", "48");
url.searchParams.set("include_route", "true");
url.searchParams.set("include_predicted_eta", "true");
url.searchParams.set("include_weather", "true");
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(); // envelope contains data
const d = json.data;
// Fields you typically map to your UI:
const vessel = d.vessel; // { imo, mmsi, name }
const pos = d.current_position; // { latitude, longitude, speed_knots, course_degrees, ... }
const route = d.route; // { departure_port, destination_port, eta, distance_nm, avg_speed_knots }
const history = d.position_history; // array of fixes
const lastPorts = d.last_port_visits; // array of recent port calls
return {
name: vessel?.name,
mmsi: vessel?.mmsi,
lat: pos?.latitude,
lon: pos?.longitude,
speed: pos?.speed_knots, // knots
course: pos?.course_degrees, // degrees
navStatus: pos?.navigational_status,
timestampUtc: pos?.timestamp_utc, // UTC string
destination: pos?.destination,
etaText: pos?.eta,
route,
history,
lastPorts
};
}
// Example invocation:
trackVessel("258785000")
.then(data => console.log("Track:", data))
.catch(err => console.error(err));
Illustrative JSON response (fields per spec)
Values are illustrative, not live data:
{
"data": {
"vessel": { "imo": "9123456", "mmsi": "258785000", "name": "SALVOR ONE" },
"current_position": {
"latitude": 37.7749,
"longitude": -122.4194,
"speed_knots": 9.2,
"course_degrees": 135,
"heading_degrees": 130,
"navigational_status": "Under way using engine",
"timestamp_utc": "2026-09-26T12:05:00Z",
"destination": "ARBUE",
"eta": "2026-09-27T08:30:00Z"
},
"position_history": [
{ "latitude": 37.88, "longitude": -122.52, "speed_knots": 10.1, "course_degrees": 132, "heading_degrees": 130, "navigational_status": "Under way using engine", "timestamp_utc": "2026-09-26T11:05:00Z", "destination": "ARBUE", "eta": "2026-09-27T08:30:00Z" }
],
"route": {
"departure_port": "USOAK",
"departure_time": "2026-09-26T05:20:00Z",
"destination_port": "ARBUE",
"eta": "2026-09-27T08:30:00Z",
"distance_nm": 310.4,
"avg_speed_knots": 9.0
},
"last_port_visits": [
{ "port_id": "USOAK", "arrival": "2026-09-25T22:05:00Z", "departure": "2026-09-26T05:20:00Z" }
]
}
}
Key fields you will actually use:
- current_position.latitude, longitude — plot on your map (WGS84 degrees)
- current_position.speed_knots, course_degrees, heading_degrees — for motion vector rendering
- current_position.navigational_status — triage (e.g., “At anchor”, “Under way using engine”)
- route.destination_port and route.eta — coordinate tugs and port services
- position_history — draw a breadcrumb trail for the last X hours
Units and conventions:
- Speed in knots, distance in nautical miles (nm)
- Bearings in degrees (0–359)
- Timestamps are UTC ISO-8601 strings
Endpoint 2: Find assist-capable assets near an incident
After you locate the casualty, you need to vector the nearest tugs or salvage vessels. GET /vessels/nearby returns all vessels within a radius around a lat/lon point. Filter by ship_type if your workflow keys on tug/salvage categories in your catalog.
HTTP request
Required: latitude, longitude
Optional: radius (default 50 NM, max 200), ship_type, limit (default 50)
cURL example (30 NM radius around a reported distress):
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/nearby?latitude=36.12&longitude=-5.35&radius=30&ship_type=Tug"
Illustrative JSON shape (values illustrative):
{
"data": {
"center": { "latitude": 36.12, "longitude": -5.35 },
"radius_nm": 30,
"total": 12,
"vessels": [
{
"imo": "9432100",
"mmsi": "224567890",
"name": "RESCUE ALFA",
"ship_type": "Tug",
"position": { "latitude": 36.18, "longitude": -5.28, "timestamp_utc": "2026-09-26T12:04:00Z" },
"distance_nm": 5.2,
"speed_knots": 11.3,
"course_degrees": 210,
"navigational_status": "Under way using engine"
}
]
}
}
What you will read from this payload:
- vessels[].distance_nm — rank by proximity
- vessels[].speed_knots and course_degrees — estimate time-to-scene
- position.timestamp_utc — ensure you use recent AIS data for decisions
Endpoint 3: Batch-track your salvage fleet
Operations centers often watch multiple assets: primary salvage tugs, escort tugs, support craft. Instead of N calls to /vessels/track, you can POST once to /vessels/fleet for aggregated positions and routes.
HTTP request
Method: POST
Body: JSON with a list of IMO/MMSI identifiers, plus flags to include positions/routes
cURL example:
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"vessels":[{"imo":"9122556"},{"mmsi":"309374000"}],"include_positions":true,"include_routes":true}' \
"https://vessels-api.com/api/V1/vessels/fleet"
Illustrative response (values illustrative):
{
"data": {
"fleet": { "total_vessels": 2, "vessels_at_sea": 1, "vessels_in_port": 1 },
"vessels": [
{
"imo": "9122556",
"mmsi": "309374000",
"name": "SALVAGE TITAN",
"position": { "latitude": 51.50, "longitude": -0.12, "speed_knots": 0.0, "course_degrees": 0, "navigational_status": "Moored", "timestamp_utc": "2026-09-26T12:05:00Z" },
"route": { "departure_port": "GBLON", "departure_time": "2026-09-25T15:00:00Z", "destination_port": "N/A", "eta": null, "distance_nm": 0, "avg_speed_knots": 0 }
}
]
}
}
Why it’s useful:
- Single request updates a wallboard of asset dots and ETAs
- fleet.* summary helps quick-read readiness and activity level
- Compatible with polling and server-side caching for dashboards
Endpoint 4: Port congestion during casualty routing
If a casualty requires towage to a port of refuge, congestion may change the plan. Use GET /ports/congestion to snapshot anchorage/berth counts and wait-time statistics.
HTTP request
Required: port_id (e.g., ARBUE)
Optional: period=24h|3d|7d
cURL example:
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/ports/congestion?port_id=ARBUE&period=7d"
Illustrative response (values illustrative):
{
"data": {
"port_id": "ARBUE",
"port_name": "Buenos Aires",
"period": "7d",
"snapshot": { "vessels_in_anchorage": 18, "vessels_at_berth": 27 },
"statistics": {
"avg_wait_time_hours_last_7d": 19.5,
"max_wait_time_hours_last_7d": 42.0,
"avg_berth_time_hours_last_7d": 21.3,
"port_calls_count": 315
}
}
}
How to apply it:
- Compare two candidate ports’ anchorage load and average wait times
- Use port_calls_count as a proxy for recent activity level
- Surface clear advisories in your ops room UI when wait times exceed thresholds
Bonus: Find a vessel quickly by name or ID
During fast-moving calls, you may not have the MMSI at hand. GET /vessels/search performs fuzzy name lookups and supports filters like flag, ship_type, and build year windows.
cURL example (fuzzy name + flag):
curl -H "X-API-Key: YOUR_API_KEY" \
"https://vessels-api.com/api/V1/vessels/search?query=salvor&flag=Panama&per_page=5"
Illustrative response (values illustrative):
{
"data": {
"vessels": [
{
"imo": "9666000",
"mmsi": "352001999",
"name": "SALVOR PRIME",
"flag": "Panama",
"vessel_type": "Tug",
"gross_tonnage": 750,
"deadweight_tonnage": 420,
"year_built": 2016,
"length_m": 35,
"width_m": 11
}
],
"pagination": { "current_page": 1, "per_page": 5, "total": 2, "last_page": 1 }
}
}
Notes that save time:
- Use per_page up to 100. Combine with page for pagination.
- Normalize case in your UI; the API does the fuzzy matching.
- Once you have the MMSI/IMO, hand off to /vessels/track for live data.
Putting it together: a minimal salvage incident flow
- Search the target if you only have a partial name (GET /vessels/search)
- Lock onto the casualty with live AIS and route context (GET /vessels/track)
- Query nearby assets that can assist (GET /vessels/nearby with ship_type filter)
- Continuously update your asset board (POST /vessels/fleet on a timer)
- Check port congestion to finalize the tow-to-port plan (GET /ports/congestion)
Operational details: units, timestamps, caching, and errors
- Units: knots for speed, nautical miles for distance, degrees for bearings, meters for dimensions in vessel particulars.
- Time: All timestamps are UTC ISO-8601. Convert in your UI if you show local timezones; ports also include timezone metadata via ports endpoints.
- Caching: For dashboards, a 15–60 second cache on /vessels/track and /vessels/nearby balances freshness with API usage. For /ports/congestion, 5–10 minutes is often sufficient.
- Pagination: /vessels/search supports page and per_page (max 100). Capture pagination.last_page for “Load more.”
- Error handling: Respect documented status codes — 400 (parameter issue), 401 (auth), 404 (not found), 422 (out of range), 429 (rate limited), 500 (server). Backoff and retry only on transient 429/500.
Example: Build a salvage-ready dashboard widget in JavaScript
This snippet ties together a casualty’s live track and the nearest assist vessels into one state object you can render on a map.
async function loadSalvageSnapshot({ casualtyMmsi, incidentLat, incidentLon }) {
const headers = { "X-API-Key": "YOUR_API_KEY" };
// 1) Live casualty track
const trackUrl = new URL("https://vessels-api.com/api/V1/vessels/track");
trackUrl.searchParams.set("mmsi", casualtyMmsi);
trackUrl.searchParams.set("hours", "24");
trackUrl.searchParams.set("include_route", "true");
trackUrl.searchParams.set("include_predicted_eta", "true");
// 2) Nearby assist assets (within 25 NM, filter to Tug)
const nearbyUrl = new URL("https://vessels-api.com/api/V1/vessels/nearby");
nearbyUrl.searchParams.set("latitude", String(incidentLat));
nearbyUrl.searchParams.set("longitude", String(incidentLon));
nearbyUrl.searchParams.set("radius", "25");
nearbyUrl.searchParams.set("ship_type", "Tug");
nearbyUrl.searchParams.set("limit", "50");
const [trackRes, nearbyRes] = await Promise.all([
fetch(trackUrl, { headers }),
fetch(nearbyUrl, { headers })
]);
if (!trackRes.ok) throw new Error(`Track error: ${trackRes.status}`);
if (!nearbyRes.ok) throw new Error(`Nearby error: ${nearbyRes.status}`);
const trackJson = await trackRes.json();
const nearbyJson = await nearbyRes.json();
const casualty = trackJson.data;
const assets = nearbyJson.data.vessels || [];
// Derive simple ETAs based on distance/speed where available
const assetsWithEta = assets.map(v => {
const speed = v.speed_knots || 0;
const distance = v.distance_nm || 0;
const etaHours = speed > 0 ? distance / speed : null;
return { ...v, eta_hours_to_scene: etaHours };
});
return {
casualty_name: casualty.vessel?.name,
casualty_position: casualty.current_position,
casualty_route: casualty.route,
assist_assets: assetsWithEta.sort((a, b) => (a.distance_nm || 0) - (b.distance_nm || 0))
};
}
Design choices for production
- Polling interval: For incident rooms, 30–60 seconds on /vessels/track works well. Use staggered polling for multiple targets.
- Fallback ID strategy: Store both IMO and MMSI. Some ships update one identifier more consistently across feeds.
- Map rendering: Course vs heading — use course_degrees for track vector, heading_degrees for bow orientation if you render ship silhouettes.
- Data validation: Discard stale positions based on timestamp_utc if they exceed your freshness SLA.
- Auditing: Persist snapshots of position_history for after-action reviews.
Port intelligence beyond congestion
If you need more context around a port of refuge selection or to coordinate arrival windows, also review:
- GET /ports — to list ports and coordinates (248 entries)
- GET /ports/data — to read live vessel counts at a single port
- GET /port/expected-arrivals — understand what is arriving soon, with ETA and origin
- GET /port/activity — recent arrivals/departures to infer berth turnarounds
Use these endpoints with lightweight caching (5–10 minutes) in planning tools.
ESG and regulatory considerations
While not core to the immediate salvage response, some teams feed incident voyage segments into compliance systems. GET /vessels/green returns IMO CII estimates and ratings (A–E) over selectable periods (24h|7d|30d|1y). This can inform sustainability reporting related to towage or post-incident voyages.
Quick-start checklist
- Base URL: https://vessels-api.com/api/V1
- Authentication: X-API-Key header
- Primary endpoints for salvage: /vessels/track, /vessels/nearby, /vessels/fleet, /ports/congestion
- Units: knots, nautical miles, degrees; timestamps in UTC
- Pagination: use page and per_page on /vessels/search
FAQ
How fresh is the AIS data and how often should I poll?
Coverage is global with near real-time refresh rates. For incident tracking, polling every 30–60 seconds is a common balance. Apply client-side caching to avoid unnecessary duplicate requests.
What if I only know the vessel name, not MMSI or IMO?
Use GET /vessels/search with query=name. The response includes imo and mmsi; feed one of them into GET /vessels/track for live data. You can filter by flag or ship_type to narrow matches.
How do I ensure I’m not acting on stale positions?
Check current_position.timestamp_utc on /vessels/track and position.timestamp_utc on /vessels/nearby. If the timestamp exceeds your freshness threshold, flag it in the UI.
Can I track many assets at once without hammering the API?
Yes. Use POST /vessels/fleet with your list of vessels and set include_positions and include_routes as needed. Cache results for short intervals.
Which fields matter for routing to a port of refuge?
From /vessels/track: route.destination_port and route.eta; from /ports/congestion: snapshot.vessels_in_anchorage and statistics.avg_wait_time_hours_last_7d. Combine them to estimate total time to alongside.
Build your salvage dashboard on a stable maritime foundation with the Vessels API. Start prototyping incident flows with GET /vessels/track and GET /vessels/nearby, then scale to full fleet views and port intelligence. Try Vessels API for free and Get started with Vessels API to ship your integration today.




