Building a fleet, keeping it current, reading what it is made of and what it has done, then using it as the unit of monitoring. The calls are in the order you would make them.Fleet IDs below are shortened for readability; the real ones are UUIDs.
Creation is one call. The vessels go in the body with the name.
201 Created, and the response carries the fleet's identifier along with what happened to each vessel:
{"meta":{"request_id":"550e8400-e29b-41d4-a716-446655440000","request_timestamp":"2026-09-08T10:15:30Z"},"data":{"fleet":{"fleet_id":"f162c3c2-cce3-4857-81a2-093dd3b50bcb","name":"Mediterranean Container Watch","description":"Container vessels under compliance review in the Med","vessel_count":2,"created_at":"2026-09-08T10:15:30Z","created_by":"j.harding@example.com"}},"vessel_results":{"requested":3,"added":2,"rejected":[{"reason":"NOT_FOUND","imo_numbers":["9169055"]}]}}
Three IMOs went in, vessel_count is 2. Nothing in the 201 tells you that, and the fleet is live either way.rejected groups by reason rather than listing one entry per vessel, so INVALID_FORMAT and NOT_FOUND each arrive once with all the IMOs that hit them.If none of the IMOs resolve, the whole call fails with 400 and no fleet is created. Partial success needs at least one vessel to land.
1
Resolve your IMOs before you send themA spreadsheet of vessel names is not a list of IMOs. Vessel Insights turns names into identifiers, and resolving them up front means you decide what to do about a missing vessel instead of missing it.
2
Send the batchOne call takes the whole list, so there is no reason to loop.
3
Reconcile against rejectedTreat it as a data-quality signal about your own list, not as an API error. A vessel that is not found today may not be one we hold.
A vessel is sold out of the fleet and two more are chartered in. One call does both, and it is the same call that renames the fleet:
At least one of name, description, add_imo and remove_imo must be present, and no IMO may appear in both lists.The response reports each vessel individually, which is a different shape from the one POST returns:
Members come enriched from the asset cache with vessel information and last known position, plus when each vessel was added and by whom.Four filters narrow the list, each taking a comma-separated list or a repeated parameter:
mti_score is both a filter and a field, and it is left out of the response entirely unless your account is entitled to MTI tier 1. A missing key means "not entitled", not "no score".For the vessel count alone, GET /v2/fleets/{fleet_id} returns the fleet with it. For a breakdown of the members, profile the fleet as below.
Only name and last_modified_at are accepted here, and -last_modified_at is the default. The richer sort and filter fields belong to the vessels endpoint.There is a name filter, matched case-insensitively on a partial string, so finding a fleet by name no longer means listing everything and matching client-side:
registration_and_flag, build_and_origin and size_and_dimensions follow in the same pattern. Unknown is where we count vessels with no value for that attribute. Where a section carries vessels_with_data, its figures rest on that many vessels.Filter first to profile part of the fleet. flag_code takes ISO 3166-1 alpha-3 codes, and vessel_type and vessel_class take type and class labels:
The events feed covers every member in one call. Here, a week of AIS gaps and zone entries:
Each event names the member it concerns in vessel_information. The fields in event_details depend on the event type; an AIS gap carries where the vessel went dark and where it reappeared (trimmed):
timestamp_start is required. Leave it out and the call fails with 400, the one validation error on this endpoint that is not a 422. Page with offset until you have read total_count events.
Running this on a schedule is a sign to subscribe
The feed suits a look back over a window you choose. If you find yourself polling it for new events, the subscription in the next section delivers them as they happen.
The reason to build a fleet at all. Point a subscription at the fleet ID instead of an IMO:
{"name":"Mediterranean fleet: high risk zone entries","active":true,"settings":{"fleet_id":"f162c3c2-cce3-4857-81a2-093dd3b50bcb","notification_callback_url":"https://webhooks.example.com/high-risk-alerts","filters":{"zones":{"active":true,"event_types":["ZONE_ENTRY"],"zone_types":["IBF"]}}}}
POST that to /notifications/v1/vessels. We resolve membership when each event is evaluated, so every change you made above takes effect without touching the subscription.
One fleet, several subscriptions
Nothing limits a fleet to a single subscription. A common shape is one fleet with two: a webhook for events that need acting on now, and an email digest for those that only need reviewing daily. Both carry the same fleet_id, so membership stays defined in one place.
The body is malformed, imo_numbers was omitted or empty, none of the supplied IMOs resolved, or an events call left out timestamp_start
403
The fleet exists but belongs to another user; fleets are private to their creator
404
No active fleet with that identifier. A soft-deleted fleet reads as absent
409
A fleet of that name already exists on your account, or the fleet you asked for is inactive
422
The fleet_id is not a UUID, a PUT body carried none of the four fields, an IMO appeared in both lists, an events window ends before it starts, or a parameter is outside its range
A partial vessel failure is not in this table. It arrives as 201 or 200 with a populated rejected or failed array.Errors & Status Codes covers the envelope these arrive in.