You need to know if a fishing vessel is near a port, whether it’s approaching, anchored, or already alongside—and you need code you can ship. By the end of this post you’ll query fishing vessels around a port, track a specific MMSI toward berth, surface port-side operational signals, and wire it all into a dashboard with concise API calls.
Problem framing: “fishing vessel near a port” as data
“Near” is both a spatial and operational state. For a fishing vessel, near a port can mean:
- Within X nautical miles of the harbor approach (spatial proximity).
- Detected at anchorage or at-berth in the port (operational proximity).
- En route with an ETA suggesting imminent arrival (temporal proximity).
With vessels-api.com, you can cover all three with a small set of endpoints: query nearby vessels by coordinates, track a specific MMSI, and read live port-side intelligence. All endpoints share a consistent JSON envelope and a single X-API-Key header.
Endpoints you’ll use
- GET /vessels/nearby — spatial proximity around a lat/lon point in NM.
- GET /vessels/track — vessel-level live position, recent route, and last port visits.
- GET /ports/data — live counts for a port (in-port, expected).
- GET /port/expected-arrivals — vessels inbound to a port with ETA and origin.
- GET /vessels/search — find a fishing vessel fast by fuzzy name, IMO, or MMSI with ship_type filter.
Supporting endpoints that scale the workflow:
- POST /vessels/fleet — batch track multiple fishing vessels (e.g., your co-op fleet) in one request.
- GET /vessels/analytics — aggregated voyage stats for a vessel or port over 24h–90d.
Prerequisites and conventions
- Base URL: https://vessels-api.com/api/V1
- Authentication: X-API-Key: YOUR_API_KEY
- Responses use the same JSON envelope: {status, success, message, data}
- Distances in nautical miles (nm), speeds in knots, timestamps in UTC ISO8601.
Find fishing vessels near a port approach
Use /vessels/nearby to query by geofence around a port’s approach buoy or anchorage. The radius is in nautical miles; limit keeps the payload tight. You can optionally filter by ship_type to “Fishing”.
Example: 30 nm radius around a port approach
curl -H "X-API-Key: YOUR_API_KEY" "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48"
Response fields to use:
- data.vessels[].mmsi / imo / name — identity keys to drill down with /vessels/track.
- data.vessels[].position.latitude / longitude / timestamp_utc — the last AIS fix near the port.
- data.vessels[].distance_nm — distance to your specified center in NM.
- data.vessels[].speed_knots, course_degrees, navigational_status — operational state hints.
Tip: set radius to match your use case. For operational readiness, 10–15 nm often maps to the pilot boarding area; for early inbound signal, 30–50 nm gives more lead time.
Track a specific fishing vessel to the pier
Once you have an MMSI from /vessels/nearby (or from /vessels/search), pivot to /vessels/track for the live position, position history (up to 168h), route metadata, and last port visits. This is the authoritative vessel-centric endpoint and your source for “near a port” transitions such as anchorage-to-berth.
Official sample: 48h tracking by MMSI
cURL (copy-paste-ready):
JSON (official sample):
{
"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:53+00:00",
"age_minutes": 5156600,
"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
}
}
How to use these fields:
- data.current_position.latitude/longitude, speed_knots, course_degrees — plot the dot and heading arrow; speed 0 can imply anchored or alongside depending on context.
- data.current_position.navigational_status — AIS status code you can surface as a badge.
- data.route — quick view of the active voyage; destination_port and eta are included when signaled.
- data.last_port_visits[] — derive “recently in port” and dwell metrics for your KPI cards.
JavaScript: fetch and classify “near a port”
This snippet calls the same official tracking endpoint and classifies the vessel as Near, In-Port, or At Sea given a target port center and threshold in NM.
<script>
// Haversine in NM for a quick "near port" check
function nmDistance(lat1, lon1, lat2, lon2) {
const toRad = (d) => d * Math.PI / 180;
const R = 3440.065; // Earth radius in nautical miles
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a = Math.sin(dLat/2)**2 +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon/2)**2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
async function trackFishingVesselNearPort() {
const API_KEY = "YOUR_API_KEY";
const url = "https://vessels-api.com/api/V1/vessels/track?mmsi=258785000&hours=48";
const res = await fetch(url, { headers: { "X-API-Key": API_KEY } });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const cp = json.data.current_position;
const vessel = json.data.vessel;
// Example: target port center (replace with your port center)
const portLat = -34.60;
const portLon = -58.38;
const nearThresholdNm = 12; // pilot boarding area range
const dist = nmDistance(cp.latitude, cp.longitude, portLat, portLon);
let state = "At Sea";
if (cp.speed_knots === 0) state = "In-Port/Anchorage";
if (dist <= nearThresholdNm) state = "Near Port";
return {
mmsi: vessel.mmsi,
imo: vessel.imo,
position: { lat: cp.latitude, lon: cp.longitude, ts: cp.timestamp_utc },
speed_knots: cp.speed_knots,
course_degrees: cp.course_degrees,
navigational_status: cp.navigational_status,
distance_to_port_nm: Number(dist.toFixed(1)),
state
};
}
trackFishingVesselNearPort()
.then(console.log)
.catch(console.error);
</script>
Notes:
- All timestamps are UTC (ISO8601). If you render local time, convert using the port timezone from /ports.
- Cache GET responses briefly only if your UI tolerates staleness. For “near a port,” low-latency queries are preferable.
Port-side signals: in-port counts and expected arrivals
To confirm a vessel is truly in-port rather than just nearby, read port-level signals alongside your vessel tracking. Combine:
- /ports/data for live counts of vessels in port and expected.
- /port/expected-arrivals for a list of inbound vessels and ETAs by port.
- /ports/congestion for anchorage/berth snapshots and historical wait-time trends.
Live port data
Use:
- data.vessels_in_port — to corroborate that your target MMSI is likely alongside or anchored.
- data.vessels_expected — to reconcile with your inbound list and avoid duplicates.
Inbound vessels and ETAs
Use:
- data.expected_arrivals[].mmsi / imo / name — match to your fishing fleet.
- data.expected_arrivals[].eta — plan for landing windows or quay-side services.
- data.expected_arrivals[].departure_port — origin context for catch provenance workflows.
Congestion lens for port readiness
Use the snapshot and statistics fields to present anchorage vs berth occupancy, and wait-time signals to stakeholders scheduling offloading and inspections for fishing vessels. The period parameter frames recent congestion dynamics.
Search specifically for fishing vessels
When you only know part of a vessel’s name or want to pull a fishing-only list for a port region, use /vessels/search with ship_type=Fishing and optional filters for flag or build year ranges.
Response fields to use:
- data.vessels[].mmsi / imo / name — feed directly into /vessels/track.
- pagination.current_page, per_page, total, last_page — implement a pager without guessing counts.
Batch-mode for a co-op or small fleet
If you manage multiple fishing vessels and need a map with live dots and route stubs, avoid N requests by using /vessels/fleet. You can ask for positions and route summaries in one call.
Use:
- data.vessels[].position — plot current dots for each MMSI/IMO.
- data.vessels[].route — draw polylines or show ETA cards if present.
- data.fleet.vessels_at_sea vs vessels_in_port — a top-line status widget.
Analytics to quantify “near port” operations
For KPIs like “time in port last 7 days” or “port calls count,” use /vessels/analytics. You can aggregate per-vessel over a period, or switch to type=port to get port-centric stats.
Use:
- statistics.total_time_in_port_hours — measure port dwell for compliance or throughput.
- statistics.port_calls_count and ports_visited — summarize port touchpoints.
- total_distance_nm, avg_speed_knots — utilization signals between landings.
Putting it together: a minimal “fishing near port” workflow
Algorithm
- Pick a port center lat/lon and a radius that represents “near” (e.g., 12 nm).
- GET /vessels/nearby with ship_type=Fishing to list candidates within the radius.
- For each candidate MMSI, GET /vessels/track to refine operational state (anchorage vs at-berth vs steaming).
- Cross-check /ports/data and /port/expected-arrivals to confirm in-port counts and ETAs.
- Optionally, GET /ports/congestion to display anchorage/berth pressure next to inbound estimates.
Data modeling tips
- Store a short-term cache (e.g., 30–60 seconds) keyed by MMSI for track data to prevent UI jitter.
- Record the last non-null route.destination_port/eta for continuity across sparse AIS updates.
- Normalize timestamps to UTC across services, then convert once at the presentation layer using the port timezone from /ports.
Practical implementation notes
- Authentication: Add X-API-Key on every request; there’s no per-endpoint auth difference.
- HTTP methods: All endpoints are GET except /vessels/fleet (POST with JSON body).
- Pagination: /vessels/search returns pagination.current_page, per_page, total, last_page. Respect per_page ≤ 100.
- Units: Distances in nautical miles (nm), speed in knots, course/heading in degrees true.
- Timestamps: All ISO8601 UTC strings (e.g., 2026-07-30T13:00:10+00:00).
Error handling
- 400 Missing/invalid parameter — check required identifiers like mmsi or latitude/longitude.
- 401 Invalid or missing X-API-Key — ensure the header is present and correct.
- 404 Vessel/port not found — retry with alternate identifier (try mmsi if imo is unknown).
- 422 Parameter out of range — radius must be ≤ 200 for /vessels/nearby; per_page ≤ 100 for search.
- 429 Rate limit exceeded — backoff with jitter; coalesce frequent GETs into a single /vessels/fleet call.
- 500 Server error — log, retry with exponential backoff.
Why this stack works for fishing vessels near ports
- Single key, single base URL, consistent JSON envelope keeps your integration surface small.
- Global AIS coverage and near real-time refresh rates let you alert as vessels break the approach line.
- Port intelligence endpoints provide the port-side truth you need to validate “near” versus “in-port.”
- Analytics enables simple KPIs for compliance and operations without building your own rollups.
FAQ
Q: How do I filter only fishing vessels in a nearby query?
A: Use /vessels/nearby with ship_type=Fishing. Example: ...nearby?latitude=...&longitude=...&radius=...&ship_type=Fishing.
Q: What timezone are timestamps in?
A: All timestamps are UTC in ISO8601 format. Convert to local port time using the timezone field from /ports or /ports/data.
Q: Can I get a vessel’s last port calls to verify repeated landings?
A: Yes. /vessels/track returns last_port_visits with arrival/departure timestamps and duration_hours when available.
Q: How often should I poll for “near port” alerts?
A: For approach alerts, a cadence of 30–60 seconds balances freshness and efficiency. Use /vessels/fleet to batch if you track multiple vessels.
Q: What’s the best way to compute distance to a port?
A: Use geodesic distance in nautical miles (Haversine) between current_position and the port center or anchorage waypoint. Compare against a threshold (e.g., 12 nm).
Next steps
Spin up your near-port alerts and dashboards with a single API key and a handful of endpoints. Start with /vessels/nearby for fishing vessels, drill down with /vessels/track, and backstop with /ports/data and /port/expected-arrivals. When you need to scale beyond one vessel, switch to /vessels/fleet. Review the specs and start building: