{"openapi": "3.1.0", "info": {"title": "SeaLagom API", "version": "2", "summary": "Navigational warnings of the whole world, with positions, shapes and an analysis of every warning.", "description": "NAVAREA and coastal navigational warnings as issued by the authorities, received around the clock.\nAuthentication: `X-API-Token: <key>` or `Authorization: Bearer <key>`. No key at all is the free tier, keyed on\nthe caller's address: 100 calls a day, at most 50 warnings a call, for 3 days from the first call or 300 calls,\nwhichever comes first (an account without an API plan gets the same tier on the account, never both added; the\nGitHub Developer allowance keeps its own requests). The free tier reads active warnings; archived warnings come\nwith a paid API plan (API Default or Full API). Free answers carry\n`X-Free-Tier-Calls-Remaining-Today`, `X-Free-Tier-Calls-Remaining-Total`, `X-Free-Tier-Records-Per-Call` and\n`X-Free-Tier-Ends`; when a quota is used the answer is HTTP 402 with what was used, when it starts again\n(`free_tier.resets_at`) and the links to pay at once (`pay.checkout`, `pay.crypto`, `pay.agent_checkout`). The\narchive in bulk, the analysis object, geo features, feeds and full route checks come with the paid plans\n(https://www.sealagom.com/api/docs/#subscription-plans). Every response\ncarries `X-API-Tokens-Used` and `X-API-Tokens-Remaining`; unknown parameter names are listed in\n`X-API-Unknown-Params`. The warnings are the authority: the analysis is machine-made and can be wrong.\n\nPaid features in one place: route analysis (POST /api/v2/route/ with an RTZ, RT3, GPX, KML, CSV or NMEA\nfile: the NAVAREAs the route crosses and every warning along it, timed from your speed and departure),\nport time zones with the UTC offset now and the next DST start and end (kept current automatically),\nthe archive in bulk, the analysis of every warning, geo features (GeoJSON, KML, Shapefile and more) and feeds.\nThis spec: https://www.sealagom.com/openapi.json (or .yaml). Code and an MCP server:\nhttps://github.com/sealagom/sealagom-api\n", "contact": {"email": "contact@sealagom.com"}, "termsOfService": "https://www.sealagom.com/terms/"}, "externalDocs": {"description": "Plans and prices for the API", "url": "https://www.sealagom.com/api/docs/#subscription-plans"}, "servers": [{"url": "https://www.sealagom.com"}], "security": [{"apiToken": []}, {"bearerAuth": []}, {}], "tags": [{"name": "warnings"}, {"name": "regions"}, {"name": "feeds"}, {"name": "route"}, {"name": "noon", "description": "Noon reports, vessels, voyages and weather. The same key; plan limits per account."}, {"name": "lookups", "description": "Ports, stations, vessels and MMSI, rigs, zones, lights, stats. The same key, one request each."}, {"name": "sky", "description": "Ready links into the sky view (the real sky and sea around a position) for a ship, a warning, a port, a place or a route. Not for navigation."}, {"name": "fleet", "description": "Your own vessels pushed in by API or a signed webhook, live in your sky and map only, with status, ETA, warnings near and along the route. Not for navigation."}, {"name": "public", "description": "No key needed."}], "paths": {"/api/v2/messages/": {"get": {"tags": ["warnings"], "summary": "Warnings, filtered and paged", "parameters": [{"name": "scope", "in": "query", "schema": {"type": "string", "enum": ["navarea", "coastal", "all"]}}, {"name": "navarea_id", "in": "query", "description": "One or more NAVAREA ids (repeat or comma-separate)", "schema": {"type": "string"}}, {"name": "coastal_id", "in": "query", "schema": {"type": "string"}}, {"name": "country", "in": "query", "description": "Country name", "partial match": null, "schema": {"type": "string"}}, {"name": "q", "in": "query", "description": "Words in the warning text (original or English)", "schema": {"type": "string"}}, {"name": "date_from", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "date_to", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "keyword", "in": "query", "description": "Keyword category or any word; repeat for several", "schema": {"type": "string"}}, {"name": "has_coordinates", "in": "query", "schema": {"type": "boolean"}}, {"name": "include_locals", "in": "query", "description": "French local (AVURNAV) warnings too", "schema": {"type": "boolean"}}, {"name": "include_archived", "in": "query", "description": "Archived warnings too: a paid API plan with archived data; without one the answer holds the warnings in force", "schema": {"type": "boolean"}}, {"name": "only_archived", "in": "query", "description": "Archived warnings only: a paid API plan with archived data; without one the answer holds the warnings in force", "schema": {"type": "boolean"}}, {"name": "status", "in": "query", "description": "in_force, cancelled, expired (comma separated)", "schema": {"type": "string"}}, {"name": "message_class", "in": "query", "description": "The type: distress, military_firing, space_debris, ...", "schema": {"type": "string"}}, {"name": "station", "in": "query", "description": "A NAVTEX station", "its region id or words of its name": null, "schema": {"type": "string"}}, {"name": "lat", "in": "query", "description": "With lon", "warnings with a position within radius_nm": null, "schema": {"type": "number"}}, {"name": "lon", "in": "query", "schema": {"type": "number"}}, {"name": "radius_nm", "in": "query", "description": "Default 30", "at most 500": null, "schema": {"type": "number"}}, {"name": "bbox", "in": "query", "description": "west,south,east,north in degrees", "schema": {"type": "string"}}, {"name": "include_coordinates", "in": "query", "description": "Paid API", "schema": {"type": "boolean"}}, {"name": "include_enhanced_coordinates", "in": "query", "description": "Full API", "schema": {"type": "boolean"}}, {"name": "include_keywords", "in": "query", "description": "Full API", "schema": {"type": "boolean"}}, {"name": "include_geo_features", "in": "query", "description": "Full API", "schema": {"type": "boolean"}}, {"name": "include_ai_analysis", "in": "query", "description": "Full API", "schema": {"type": "boolean"}}, {"name": "ai_severity", "in": "query", "description": "critical", "high": null, "moderate": null, "low": null, "info; repeat for several": null, "schema": {"type": "string"}}, {"name": "ai_category", "in": "query", "schema": {"type": "string"}}, {"name": "ai_status", "in": "query", "schema": {"type": "string"}}, {"name": "ai_in_force", "in": "query", "description": "Only warnings in force right now", "schema": {"type": "boolean"}}, {"name": "expires_within_hours", "in": "query", "schema": {"type": "integer"}}, {"name": "expires_after", "in": "query", "schema": {"type": "string"}}, {"name": "expires_before", "in": "query", "schema": {"type": "string"}}, {"name": "exclude_routine", "in": "query", "description": "Leave out ice reports", "rig lists": null, "in-force lists": null, "schema": {"type": "boolean"}}, {"name": "ai_has", "in": "query", "schema": {"type": "string"}}, {"name": "min_keep_clear_nm", "in": "query", "schema": {"type": "number"}}, {"name": "topic", "in": "query", "description": "A feed", "ice or a themed feed slug": null, "schema": {"type": "string"}}, {"name": "ice_type", "in": "query", "schema": {"type": "string"}}, {"name": "settings", "in": "query", "description": "off: ignore the key's saved settings for one call", "schema": {"type": "string"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "default": 1}}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}], "responses": {"200": {"description": "A page of warnings", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WarningPage"}}}}, "401": {"description": "Missing or wrong key"}, "403": {"description": "The plan does not include this (include_all on the free plan)"}, "429": {"description": "Allowance or rate limit reached (archive questions: 30 a minute per address)"}}}}, "/api/v2/navarea/": {"get": {"tags": ["regions"], "summary": "NAVAREA regions, with their warnings on request", "parameters": [{"name": "id", "in": "query", "schema": {"type": "integer"}}, {"name": "include_messages", "in": "query", "schema": {"type": "boolean"}}, {"name": "include_all", "in": "query", "description": "Paid API", "schema": {"type": "boolean"}}, {"name": "page", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "A page of regions", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RegionPage"}}}}}}}, "/api/v2/navarea/{id}/": {"get": {"tags": ["regions"], "summary": "One NAVAREA", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "The region", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Region"}}}}}}}, "/api/v2/coastal/": {"get": {"tags": ["regions"], "summary": "Coastal regions (by country), with their warnings on request", "parameters": [{"name": "country", "in": "query", "schema": {"type": "string"}}, {"name": "include_messages", "in": "query", "schema": {"type": "boolean"}}, {"name": "include_locals", "in": "query", "schema": {"type": "boolean"}}, {"name": "page", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "A page of regions", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RegionPage"}}}}}}}, "/api/v2/coastal/{id}/": {"get": {"tags": ["regions"], "summary": "One coastal region", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "The region", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Region"}}}}}}}, "/api/v2/ice/": {"get": {"tags": ["feeds"], "summary": "The ice feed (Full API)", "parameters": [{"name": "ice_type", "in": "query", "schema": {"type": "string"}}, {"name": "output", "in": "query", "schema": {"type": "string", "enum": ["json", "geojson"]}}], "responses": {"200": {"description": "Warnings about ice", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WarningPage"}}}}}}}, "/api/v2/feeds/": {"get": {"tags": ["feeds", "public"], "summary": "Every feed with its endpoint and the number of warnings in force", "security": [], "responses": {"200": {"description": "The catalogue"}}}}, "/api/v2/feeds/{slug}/": {"get": {"tags": ["feeds"], "summary": "A themed feed (military, cables, offshore...) (Full API)", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "category", "in": "query", "schema": {"type": "string"}}, {"name": "output", "in": "query", "schema": {"type": "string", "enum": ["json", "geojson"]}}], "responses": {"200": {"description": "The feed's warnings", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WarningPage"}}}}}}}, "/api/v2/route/": {"post": {"tags": ["route"], "summary": "Send a route, get the NAVAREAs it crosses and the warnings along it", "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary", "description": "RTZ", "RT3": null, "GPX": null, "KML": null, "CSV or NMEA route file (up to 5 MB)": null}, "corridor_nm": {"type": "number", "default": 10}, "speed_kn": {"type": "number", "default": 12}, "departure": {"type": "string", "format": "date-time"}}}}, "application/json": {"schema": {"$ref": "#/components/schemas/RouteRequest"}}}}, "responses": {"200": {"description": "The route result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RouteResult"}}}}, "400": {"description": "The file could not be read", "or fewer than two waypoints": null}}}}, "/api/v2/drop/{token}/route/": {"post": {"tags": ["route"], "summary": "The same route check with the key in the address (a drop link for tools that can only POST a file)", "security": [], "parameters": [{"name": "token", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary"}, "corridor_nm": {"type": "number"}}}}}}, "responses": {"200": {"description": "The route result", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RouteResult"}}}}}}}, "/api/map/account/": {"get": {"tags": ["noon"], "summary": "The account of the key: vessels, voyages, fleets, invitations, plan usage", "responses": {"200": {"description": "The account"}}}}, "/api/map/vessels/": {"get": {"tags": ["noon"], "summary": "Your vessels (and the ones shared with you)", "responses": {"200": {"description": "{vessels: [...]}"}}}, "post": {"tags": ["noon"], "summary": "Add a vessel", "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["name"], "properties": {"name": {"type": "string"}, "imo": {"type": "string"}, "mmsi": {"type": "string"}, "call_sign": {"type": "string"}, "flag": {"type": "string"}, "vessel_type": {"type": "string"}, "fleet": {"type": "integer", "description": "fleet id", "optional": null}}}}}}, "responses": {"201": {"description": "The vessel", "with public_id": null}}}}, "/api/map/vessels/{public_id}/voyages/": {"get": {"tags": ["noon"], "summary": "The voyages of a vessel", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "{voyages: [...]}"}}}, "post": {"tags": ["noon"], "summary": "Open a voyage", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"number": {"type": "string"}, "name": {"type": "string"}, "departure_name": {"type": "string", "description": "port name or slug"}, "arrival_name": {"type": "string"}, "charterer": {"type": "string"}, "etd": {"type": "string", "format": "date-time"}, "eta": {"type": "string", "format": "date-time"}, "waypoints": {"type": "array", "items": {"type": "object", "properties": {"lat": {"type": "number"}, "lon": {"type": "number"}}}, "description": "the planned route", "optional": null}}}}}}, "responses": {"201": {"description": "The voyage", "with public_id": null}}}}, "/api/map/voyages/{public_id}/": {"get": {"tags": ["noon"], "summary": "One voyage with its dashboard figures", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "The voyage"}}}}, "/api/map/voyages/{public_id}/reports/": {"get": {"tags": ["noon"], "summary": "The reports of a voyage (noon, departure, arrival, position, bunkering...)", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "{reports: [...]}"}}}, "post": {"tags": ["noon"], "summary": "Post a report (a bridge PC, a GPS logger, a script)", "description": "The figures go in `values` under the vessel's report item keys (the report form at\n/report-form/ lists them: speed, distance, rpm, fuel and so on). A report of the same kind and\ntime replaces the earlier one. When the figures do not add up the answer is 409 with `checks`;\nsend `confirm: true` to save anyway.\n", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"kind": {"type": "string", "default": "noon", "enum": ["noon", "departure", "arrival", "position", "bunkering", "cargo", "eosp", "sosp", "anchoring", "drifting", "berthing", "unberthing", "shifting", "canal", "deviation", "stoppage"]}, "reported_at": {"type": "string", "format": "date-time", "description": "UTC; default now"}, "lat": {"type": "number"}, "lon": {"type": "number"}, "values": {"type": "object", "additionalProperties": true}, "confirm": {"type": "boolean"}}}}}}, "responses": {"201": {"description": "The report with the computed figures"}, "402": {"description": "The report allowance of the plan is used up"}, "409": {"description": "Figures to check; confirm to save"}}}}, "/api/map/voyages/{public_id}/report-form/": {"get": {"tags": ["noon"], "summary": "The report items (keys, labels, units) this vessel expects", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "The form definition"}}}}, "/api/map/voyages/{public_id}/weather-track/": {"get": {"tags": ["noon"], "summary": "The weather along the voyage's reported track", "parameters": [{"name": "public_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}], "responses": {"200": {"description": "Weather per report position and time"}}}}, "/api/map/weather/": {"get": {"tags": ["noon"], "summary": "Wind, sea and the forecast at a position and time", "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "time", "in": "query", "schema": {"type": "string", "format": "date-time", "description": "UTC; default now"}}], "responses": {"200": {"description": "{time, at: {...}, series: [...], ocean, source}"}}}}, "/api/v2/route/convert/": {"post": {"tags": ["route"], "summary": "Route converter: any route file in, RTZ, GPX, KML, CSV or NMEA out", "parameters": [{"name": "to", "in": "query", "required": true, "schema": {"type": "string", "enum": ["rtz", "gpx", "kml", "csv", "nmea", "json"]}}], "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary", "description": "RTZ, RT3, GPX, KML, CSV or NMEA"}}}}, "application/json": {"schema": {"type": "object", "properties": {"name": {"type": "string"}, "waypoints": {"type": "array", "items": {"type": "object", "required": ["lat", "lon"], "properties": {"lat": {"type": "number"}, "lon": {"type": "number"}, "name": {"type": "string"}}}}}}}}}, "responses": {"200": {"description": "The converted file (Content-Disposition attachment; header X-Waypoints)"}}}}, "/api/v2/sky/link/": {"get": {"tags": ["sky"], "summary": "A ready link into the sky view for a ship, a warning, a port, a place or a position", "description": "Give one of: vessel (name), mmsi or imo (aboard=1 for the view from her bridge); warning (number) with region\n(NAVAREA XII or a coastal country), or q (words of a warning in force); port (name, country to narrow) or locode;\nplace (a well-known place; lat and lon when it is not on the list); lat and lon (a position). The view stands\nwhere the target can be seen: a ship 1 nm off her starboard beam looking at her (aboard: on her bridge looking\nahead), a warning 1 nm off its position or just outside the edge of its area at sea (0.4 nm) looking in, a port off\nits approach looking in. Ships come from the live AIS feed (reports of the last 30 minutes), placed where she is\nnow (her report carried forward on her course, at most 15 minutes); below Contributor a key sees the same half of\nthe ships as the free map (403 for the other half). The link is signed (sig=): anyone may open it, at no cost to\ntheir own allowance. Nothing is stored. Not for navigation.\n", "parameters": [{"name": "vessel", "in": "query", "schema": {"type": "string"}}, {"name": "mmsi", "in": "query", "schema": {"type": "string", "pattern": "^[0-9]{9}$"}}, {"name": "imo", "in": "query", "schema": {"type": "string", "pattern": "^[0-9]{7}$"}}, {"name": "aboard", "in": "query", "schema": {"type": "integer", "enum": [0, 1]}}, {"name": "warning", "in": "query", "schema": {"type": "string"}, "description": "The warning's number, e.g. 123/26"}, {"name": "region", "in": "query", "schema": {"type": "string"}, "description": "NAVAREA XII, or a coastal country"}, {"name": "q", "in": "query", "schema": {"type": "string"}, "description": "Words of a warning in force"}, {"name": "port", "in": "query", "schema": {"type": "string"}}, {"name": "locode", "in": "query", "schema": {"type": "string"}, "description": "UN/LOCODE, e.g. SGSIN"}, {"name": "country", "in": "query", "schema": {"type": "string"}}, {"name": "place", "in": "query", "schema": {"type": "string"}, "description": "A well-known place, e.g. Cape Horn"}, {"name": "lat", "in": "query", "schema": {"type": "number", "minimum": -90, "maximum": 90}}, {"name": "lon", "in": "query", "schema": {"type": "number", "minimum": -180, "maximum": 180}}, {"name": "look", "in": "query", "schema": {"type": "number", "minimum": 0, "maximum": 360}, "description": "A position's bearing to look along (ignored when not a number from 0 to 360)"}], "responses": {"200": {"description": "{url (absolute), path, at: {lat, lon}, look: {az, alt, fov}, focus (\"ship:<MMSI>\", \"warning:<scope>:<id>\",\n\"port:<slug>\" or null), aboard, target: {kind: vessel|warning|port|place|position, title, lat, lon,\napproximate}, how, note: \"Not for navigation.\"}\n"}, "400": {"description": "No target given"}, "403": {"description": "A ship in the half of AIS this key's plan does not show"}, "404": {"description": "Nothing matches (no such ship on AIS now", "no warning in force with that number": null, "no such port)": null}, "409": {"description": "Several match (two ships of one name, two warnings of one number, two positions): {detail, choices: [..]}"}}}}, "/api/v2/sky/route/": {"post": {"tags": ["sky", "route"], "summary": "A route in: its sky link (standing on the first waypoint, the route drawn on the sea) and RTZ and GPX out", "description": "Read with the map's own parsers (RTZ, RT3, GPX, KML, CSV, NMEA and more; 2 MB, 500 waypoints) or from JSON.\nLegs are rhumb lines unless the file or leg_types marks a great circle (also an RTZ defaultWaypoint's leg). An\nRTZ's plan is kept: each waypoint's turn radius, each leg's cross-track limits, and the schedule (planned speeds\nfrom scheduleElement speed, calculated before manual, never speedMin or speedMax; the file's ETD and ETAs win;\ntime added up leg by leg). The sky link carries routes of up to 200 waypoints (route_in_link). rtz is RTZ 1.1\nwith the great-circle legs, radii, XTDs and planned speeds kept, gpx a GPX 1.1 route. Nothing is stored. Not for\nnavigation.\n", "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary"}}}}, "application/json": {"schema": {"type": "object", "required": ["waypoints"], "properties": {"name": {"type": "string"}, "waypoints": {"type": "array", "minItems": 2, "maxItems": 500, "items": {"type": "object", "required": ["lat", "lon"], "properties": {"lat": {"type": "number"}, "lon": {"type": "number"}, "name": {"type": "string"}}}}, "leg_types": {"type": "array", "items": {"type": "string", "enum": ["RL", "GC"]}, "description": "One per leg (waypoints - 1)"}}}}}}, "responses": {"200": {"description": "{name, waypoints: [{lat, lon, name, radius_nm?}], leg_types: [RL|GC] | null, distance_nm,\nlegs: [{course, distance_nm, type, speed_kn?, hours?, xtd_port_nm?, xtd_stbd_nm?}],\nspeed_kn (the whole distance over the whole planned time, when every leg is timed) | null, etd (ISO) | null,\nsky_url, route_in_link, rtz (text), gpx (text), note}\n"}, "400": {"description": "The file cannot be read, is larger than 2 MB, or has fewer than two finite waypoints"}}}}, "/api/v2/near/": {"get": {"tags": ["lookups"], "summary": "Warnings in force near a position, with distance and bearing", "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "radius_nm", "in": "query", "schema": {"type": "number", "default": 30, "maximum": 200}}], "responses": {"200": {"description": "{count, warnings: [...]}"}}}}, "/api/v2/ports/": {"get": {"tags": ["lookups"], "summary": "Ports by name, UN/LOCODE or country, or the nearest to a position", "parameters": [{"name": "q", "in": "query", "schema": {"type": "string"}}, {"name": "lat", "in": "query", "schema": {"type": "number"}}, {"name": "lon", "in": "query", "schema": {"type": "number"}}, {"name": "sort", "in": "query", "schema": {"type": "string", "enum": ["rank"]}}, {"name": "top", "in": "query", "schema": {"type": "integer", "enum": [1], "description": "the main ports only"}}, {"name": "page", "in": "query", "schema": {"type": "integer", "default": 1}}, {"name": "page_size", "in": "query", "schema": {"type": "integer", "default": 40, "maximum": 100}}], "responses": {"200": {"description": "{ports: [{slug, name, country_code, un_locode, lat_decimal, lon_decimal, harbor_size, navarea_roman, rank}], total_count, page, total_pages}"}}}}, "/api/v2/ports/{slug}/": {"get": {"tags": ["lookups"], "summary": "One port: time zone with the UTC offset now and the next DST start and end, depths, approach and pilotage, VTS, anchorages, restrictions, facilities, warnings, routes", "parameters": [{"name": "slug", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "{port: {...}, warning_messages, attached_resources, related_resources, routes}"}}}}, "/api/v2/port-distances/": {"get": {"tags": ["lookups"], "summary": "Sea distance between two ports along shared ECDIS routes", "parameters": [{"name": "from", "in": "query", "schema": {"type": "string", "description": "port slug"}}, {"name": "to", "in": "query", "schema": {"type": "string"}}, {"name": "port", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "Distances in NM"}}}}, "/api/v2/stations/": {"get": {"tags": ["lookups"], "summary": "Every rescue coordination centre and DSC coast station (NGA Pub 117), with MMSI", "responses": {"200": {"description": "{count, stations: [{id, kind, name, country, mmsi, lat, lon, bands, max_range_nm}]}"}}}}, "/api/v2/stations/near/": {"get": {"tags": ["lookups"], "summary": "Rescue centres covering a position and DSC coast stations in range", "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number"}}, {"name": "radius_nm", "in": "query", "schema": {"type": "number", "default": 200, "maximum": 600}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 12, "maximum": 30}}], "responses": {"200": {"description": "{rcc_covering, rcc_near, dsc_near, test_nearest}"}}}}, "/api/v2/stations/{id}/": {"get": {"tags": ["lookups"], "summary": "One station with bands, watch times and contacts", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "integer"}}], "responses": {"200": {"description": "The station"}}}}, "/api/v2/vessels/": {"get": {"tags": ["lookups"], "summary": "A vessel by name, call sign or MMSI: the warnings naming it, its rows, stations with that MMSI, live AIS when on", "parameters": [{"name": "q", "in": "query", "required": true, "schema": {"type": "string", "description": "name, call sign or MMSI (3+ characters)"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "maximum": 200}}], "responses": {"200": {"description": "{query, mmsi, vessels: [{name, mmsi, call_sign, imo, flag, type, warnings}], warnings: [{scope, region, region_id, number, in_force, added_on, url, vessels, headline*, severity*, status*, mariner_action*}], stations, ais, ais_live, count, meta?} (* Full API)"}}}}, "/api/v2/vessels/{mmsi}/": {"get": {"tags": ["lookups"], "summary": "The same for one MMSI", "parameters": [{"name": "mmsi", "in": "path", "required": true, "schema": {"type": "string", "description": "7 to 9 digits", "leading zeros kept (coast stations start with 00)": null}}], "responses": {"200": {"description": "As /api/v2/vessels/"}}}}, "/api/v2/rigs/": {"get": {"tags": ["lookups"], "summary": "Mobile offshore drilling units with their last reported positions", "responses": {"200": {"description": "{count, rigs: [...]}"}}}}, "/api/v2/zones/": {"get": {"tags": ["lookups"], "summary": "Nautical time zones and satcom footprints", "responses": {"200": {"description": "{zones, satcom}"}}}}, "/api/v2/navarea-zones/": {"get": {"tags": ["lookups"], "summary": "The 21 NAVAREAs as GeoJSON (limits from WMO-No. 558), with coordinator and warnings in force", "responses": {"200": {"description": "A GeoJSON FeatureCollection"}}}}, "/api/v2/lights/": {"get": {"tags": ["lookups"], "summary": "Aids to navigation reported out of order (Full API; other plans get count and locked=true)", "parameters": [{"name": "scope", "in": "query", "schema": {"type": "string", "enum": ["navarea", "coastal"]}}, {"name": "region_id", "in": "query", "schema": {"type": "integer"}}, {"name": "country", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "{count, conditions, locked, regions, aids}"}}}}, "/api/v2/stats/": {"get": {"tags": ["lookups"], "summary": "The public figures of the service", "responses": {"200": {"description": "The figures"}}}}, "/feeds/warnings.xml": {"get": {"tags": ["public"], "summary": "RSS of the newest 100 warnings (also /feeds/navarea/{id}.xml and /feeds/coastal/{id}.xml)", "security": [], "responses": {"200": {"description": "RSS 2.0", "content": {"application/rss+xml": {}}}}}}, "/feeds/warnings.txt": {"get": {"tags": ["public"], "summary": "The newest warnings as plain text (?navarea=, ?coastal=, ?limit=)", "security": [], "responses": {"200": {"description": "text/plain"}}}}, "/api/public/sky/weather/": {"get": {"tags": ["public"], "summary": "Weather, sea and time zone now at one position (the sky explorer's Weather here and Clock tools)", "description": "The position is rounded to 0.1 degree; each cell is kept 15 minutes (Cache-Control public, max-age=900).\nAir from Open-Meteo current conditions (OpenWeather when Open-Meteo fails), sea from the Open-Meteo marine\nmodel (null on land). Time zone from the nearest port within 60 nm that has one (kind \"port\", IANA name and\nthe offset in force now), otherwise nautical zone time, one hour per 15 degrees of longitude (kind \"nautical\").\nWind in knots and degrees true it comes from; stars \"good\" (cloud under 30 % and visibility 10 km or more),\n\"poor\" (cloud over 70 % or rain), else \"fair\". When the weather source fails the answer is still 200 with\nair null and a message, kept 2 minutes. Browser use from sealagom.com pages; at most 10 requests in 10 s.\n", "security": [], "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number", "minimum": -90, "maximum": 90}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number", "minimum": -180, "maximum": 180}}], "responses": {"200": {"description": "{lat, lon, time (ISO UTC), tz: {name, offset_min, kind, label, port?: {name, distance_nm}},\nair: {temp_c, feels_c, wind_kn, wind_dir, gust_kn, beaufort, pressure_hpa, humidity, cloud_pct,\nvisibility_km, precip_mm, weather} or null, sea: {wave_m, wave_dir, swell_m, swell_dir, swell_period_s,\nsea_temp_c} or null, stars, sources, message?}\n"}, "400": {"description": "lat or lon missing or out of range"}, "429": {"description": "Too many requests (Retry-After)"}}}}, "/api/public/sky/surface/": {"get": {"tags": ["public"], "summary": "Sea, coast or land at one position, with the distance to the nearest coastline", "description": "Natural Earth 1:10m land and minor islands with lakes of 100 km2 and more as water (public domain), good to\na few hundred metres at the shore; rivers and canals read as land.\n\"land\" inside the land more than 0.5 nm from the shore, \"coast\" at sea within 12 nm of land or on land within\n0.5 nm of the shore, \"sea\" further out. coast_nm is great-circle nautical miles (0.1 nm under 100 nm).\nCache-Control public, max-age=86400.\n", "security": [], "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number", "minimum": -90, "maximum": 90}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number", "minimum": -180, "maximum": 180}}], "responses": {"200": {"description": "{kind: sea|coast|land, coast_nm, land: true|false}"}, "400": {"description": "lat or lon missing or out of range"}}}}, "/api/next-auth/sky/scene/": {"get": {"tags": ["public"], "summary": "Ships, warnings, rigs, ports and coast stations around a position, for the sky explorer's scene", "description": "Signed-in session on sealagom.com or signed out; everything in it is what the map shows the same person.\nShips are the live AIS ships within r: every ship for Contributor plans, otherwise the same half the\npublic map shows (length_m null). Warnings are every NAVAREA and coastal warning in force within 200 nm,\nwhatever r is (a day's run at 8 knots), nearest first, at most 300, free for everyone: the nearest point and\nits distance, within 20 nm the outline as it lies on the water (parts), and launch when a rocket launch's\nhazard area is linked to it (see /api/public/space/launches/). Rigs are the active MODU catalogue; ports within r + 10 nm; stations the DSC coast stations (NGA\nPub 117) whose band range covers the position, vhf [70] when the position is within its VHF range. lights is always\nempty (the site has no list of lights). The position is snapped to a 0.05 degree cell (lat and lon in the\nanswer are the cell's, distances are from it); each cell, radius and plan tier is kept 60 s.\nCache-Control private, max-age=30.\n", "security": [], "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number", "minimum": -90, "maximum": 90}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number", "minimum": -180, "maximum": 180}}, {"name": "r", "in": "query", "schema": {"type": "number", "default": 15, "minimum": 1, "maximum": 40}, "description": "Radius in nm", "rounded and clamped to 1-40": null}], "responses": {"200": {"description": "{lat, lon, r_nm, tier: free|contributor, surface: {kind, coast_nm, land},\nships: [{mmsi, name, type: cargo|tanker|passenger|fishing|tug|sailing|pleasure|hsc|other, lat, lon, cog,\nsog_kn, heading, length_m, nav_status, age_s}],\nwarnings: [{id: \"navarea:123\", scope, region, number, title, headline, lat, lon (the nearest point),\ndistance_nm, url, parts?: [{t: point|line|area, pts: [[lat, lon], ...]}] (within 20 nm),\nlaunch?: {id, mission, rocket, provider, net, window_start, window_end, window, line}}],\nrigs: [{id, name, lat, lon, kind: platform|fpso|rig|other, distance_nm, url}], lights: [],\nports: [{slug, name, lat, lon, size, rank, distance_nm}],\nstations: [{name, lat, lon, vhf, mmsi, hours, bands, range_nm, distance_nm, position_approximate}],\ngenerated (ISO UTC)}\n"}, "400": {"description": "lat", "lon or r missing or not a number": null, "or out of range": null}}}}, "/api/next-auth/sky/route/import/": {"post": {"tags": ["public"], "summary": "A route file read for the sky view's sea (the website's own call)", "description": "Signed-in session on sealagom.com or signed out, with the site's CSRF token. The map's parsers and limits (2 MB,\n500 waypoints); the file is read and forgotten, nothing is stored. Each file read counts one \"route\" of the sky's\nallowance (the founder page's): 30 a day Full Contributor, 150 Fleet, 500 Complete, 1,000 Fleet Pro, none for staff\nand licenses; 5 in the 15 minutes of full access everyone else has (429 above it, with the next plan or, at the\ntop, contact us). A file that cannot be read is not counted. Programs use POST /api/v2/sky/route/ with a key\ninstead. Not for navigation.\n", "security": [], "requestBody": {"content": {"multipart/form-data": {"schema": {"type": "object", "properties": {"file": {"type": "string", "format": "binary"}}}}}}, "responses": {"200": {"description": "{name, waypoints, leg_types, distance_nm, legs: [{course, distance_nm, type, speed_kn?, hours?, xtd_port_nm?, xtd_stbd_nm?}], speed_kn, etd, sky: {at: {lat, lon}, look}, note}"}, "400": {"description": "The file cannot be read"}, "429": {"description": "The allowance is used: {detail, limit: {status_text, label, url}}"}}}}, "/api/next-auth/sky/link/open/": {"get": {"tags": ["public"], "summary": "May the sky view stand where a sky link says (the website's own call)", "description": "The founder page asks this before it follows a link's at= (or route=). A link the server made (LagoPal, the API:\nits sig= matches) opens for anyone at no cost. A link typed or changed by hand counts one typed position of the\nsky's allowance (the same place again counts once). Not for navigation.\n", "security": [], "responses": {"200": {"description": "{ok: true, signed}"}, "403": {"description": "Not on this plan: {ok: false, detail, next, href}"}, "429": {"description": "The allowance is used: {ok: false, detail, next, href | contact}"}}}}, "/api/next-auth/sky/moment/": {"get": {"tags": ["public"], "summary": "Beta, closed: what the site knows about one place at one moment (weather, warnings in force, ships)", "x-beta": true, "description": "Beta. Not open yet: it answers staff of sealagom.com only (404 for everyone else) and will become part of a\npaid API plan. The weather then is the Open-Meteo model hour nearest t (the forecast model for the last 60\ndays and the next 7, the ERA5 archive back to 1940; the archive has no visibility; the sea from the marine\nmodel, null on land or before its records). Warnings in force at t within r: archived warnings added on or\nbefore t and archived after it, and live warnings added on or before t (the site's own dates, nearest\nfirst, at most 40). Ships from the site's AIS history (a snapshot every 15 minutes, the one at or before t),\nwith the map's plan rule (every ship for Contributor plans, otherwise the public half); empty with\nships_reason when there is no snapshot. parts says the source of each part and how far its own time is from\nt. The position is snapped to a 0.05 degree cell. Cache-Control private, no-store.\n", "security": [], "parameters": [{"name": "lat", "in": "query", "required": true, "schema": {"type": "number", "minimum": -90, "maximum": 90}}, {"name": "lon", "in": "query", "required": true, "schema": {"type": "number", "minimum": -180, "maximum": 180}}, {"name": "t", "in": "query", "required": true, "schema": {"type": "string", "format": "date-time"}, "description": "ISO 8601 UTC, from 1940-01-01 to 7 days ahead, e.g. 2026-10-20T22:00:00Z"}, {"name": "r", "in": "query", "schema": {"type": "number", "default": 15, "minimum": 1, "maximum": 40}, "description": "Radius in nm", "rounded and clamped to 1-40": null}], "responses": {"200": {"description": "{lat, lon, t, r_nm,\nweather: {hour, model: forecast|archive, air: {temp_c, wind_kn, wind_dir, gust_kn, beaufort, cloud_pct,\nvisibility_km, pressure_hpa, humidity, precip_mm, weather} or null, sea: {wave_m, wave_dir, wave_period_s,\nswell_m, swell_dir, swell_period_s, sea_temp_c} or null} or null,\nwarnings: [{id, scope, series, number, title, headline, lat, lon, distance_nm, from, until, archived, url}],\nsea_warnings: [the same warnings in force at t out to 200 nm, in the form of the scene's warnings],\nships: [{mmsi, name, type, lat, lon, cog, sog_kn, heading, length_m, nav_status, age_s}], ships_reason?,\nparts: {weather|warnings|ships: {source, gap}}, sources}\n"}, "400": {"description": "lat", "lon": null, "t or r missing or out of range": null}, "404": {"description": "Not open to this account (beta)"}}}}, "/api/public/sky/space/": {"get": {"tags": ["public"], "summary": "Objects in orbit for the sky's space layers, now and a minute later (SGP4)", "description": "Groups: bright (CelesTrak visual, the brightest objects), stations (the stations' modules and visiting craft,\nfree flyers only), recent (launched in the last 30 days), rocket (rocket bodies: those of the groups above,\nand every rocket body in orbit from Space-Track when the site's account is set), debris (the Fengyun 1C,\nCosmos 2251 and Iridium 33 debris clouds). Starlink, the ISS, Hubble and Tiangong are never in them (their\nown endpoints). Element sets fetched at most every 6 hours; positions to the minute on the 6371 km sphere,\nintegers in 1/scale degree. m works as for /api/public/sky/starlink/. Cache-Control public, max-age=60.\n", "security": [], "parameters": [{"name": "g", "in": "query", "required": true, "schema": {"type": "string", "enum": ["bright", "stations", "recent", "rocket", "debris"]}}, {"name": "m", "in": "query", "schema": {"type": "integer"}, "description": "Unix minute", "within a few minutes of now": null}], "responses": {"200": {"description": "{g, t, step, count, scale, lat, lon, lat1, lon1, alt, norad, v, epoch_age_h, available, stale, fetched_age_h, source}"}, "400": {"description": "Unknown group"}, "503": {"description": "The element sets are not available yet"}}}}, "/api/public/sky/space/meta/": {"get": {"tags": ["public"], "summary": "Names and facts of a space group's objects (SATCAT)", "description": "Arrays in the order of the element sets: norad, name, intl (international designator), type (PAY, R/B, DEB,\nUNK), owner (SATCAT owner code), launch (date), size (small, medium, large from the radar cross-section).\nPublic for 6 hours when v is the current version (the positions give it), else 60 s.\n", "security": [], "parameters": [{"name": "g", "in": "query", "required": true, "schema": {"type": "string", "enum": ["bright", "stations", "recent", "rocket", "debris"]}}, {"name": "v", "in": "query", "schema": {"type": "integer"}}], "responses": {"200": {"description": "{v, count, norad, name, intl, type, owner, launch, size}"}}}}, "/api/public/space/launches/": {"get": {"tags": ["public"], "summary": "Rocket launches of every agency and company, with the warnings of their hazard areas at sea", "description": "From Launch Library 2 (The Space Devs, free to use, credit to them), refreshed hourly by the site; never\nfetched for a request. Default span: net from 7 days ago to 60 days ahead, soonest first. warnings lists the\nNAVAREA and coastal warnings the site linked to the launch: launch wording, one of the warning's windows\nholds the launch time and opens within an hour of the launch window, an area within 1,000 nm of the pad,\nand no other launch fits as well. Landings include SpaceX droneships (name; their position is not\npublished, downrange_km is) and capsule splashdowns. Cache-Control public, max-age=300.\n", "security": [], "parameters": [{"name": "from", "in": "query", "schema": {"type": "string"}, "description": "Date or ISO time UTC (default 7 days ago)"}, {"name": "to", "in": "query", "schema": {"type": "string"}, "description": "Date or ISO time UTC (default 60 days ahead, at most 400 days after from)"}, {"name": "provider", "in": "query", "schema": {"type": "string"}, "description": "Part of the provider's name or its abbreviation, e.g. SpaceX, CASC, ISRO"}, {"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50, "minimum": 1, "maximum": 100}}], "responses": {"200": {"description": "{launches: [{id, name, mission, mission_type, orbit, rocket, provider, provider_abbrev, provider_type,\nagencies, status, status_name, net, net_precision, window_start, window_end,\npad: {name, location, country, lat, lon},\nlandings: [{stage, serial, attempt, success, place, abbrev, lat, lon, downrange_km, type, when, spacecraft?}],\nwarnings: [{scope, region_id, region, number, title, headline, url, archived, distance_nm, window_start,\nwindow_end}]}], count, from, to, generated, source, terms}\n"}, "400": {"description": "from", "to or limit not understood": null}}}}, "/api/public/space/launches/{id}/": {"get": {"tags": ["public"], "summary": "One launch (the Launch Library 2 id) with its hazard warnings", "security": [], "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The list's launch plus description, line (the warning page's line) and updated"}, "404": {"description": "Unknown launch"}}}}, "/api/public/space/reentries/": {"get": {"tags": ["public"], "summary": "Re-entry predictions (Space-Track TIP), when the site's Space-Track account is set", "description": "{available: false} until then. Otherwise the newest TIP message per object with a predicted re-entry from 3\ndays ago on: lat and lon are the predicted point at decay_utc; the object may come down anywhere along its\ntrack within plus or minus window_min minutes. Source Space-Track.org (USSPACECOM). Public, max-age=300.\n", "security": [], "responses": {"200": {"description": "{available, reentries: [{norad, name, intl, type, country, decay_utc, window_min, lat, lon, direction, high_interest, message_utc}], source}"}}}}, "/api/public/aton-faults/": {"get": {"tags": ["public"], "summary": "Lights and buoys out of order in Finnish waters (Fintraffic Digitraffic), not yet repaired", "description": "Fetched by the site from Fintraffic Digitraffic every 10 minutes; never fetched for a request. Faults still\nopen, sea and inland, in English; names of marks and fairways are Finnish, name_sv / fairway_sv the Swedish\nname when it differs. Licence CC BY 4.0: show credit with its link wherever the data is shown or passed on.\nCache-Control public, max-age=600.\n", "security": [], "responses": {"200": {"description": "{faults: [{id, lat, lon, fault, since, name, name_sv, aton_type, aton_id, fairway, fairway_sv, fairway_no,\narea}], count, updated_at, data_at, available, credit: {source, credit, url, licence, licence_url,\nsource_words, licence_words, changes}, credits, source, source_url, note}\n"}}}}, "/api/public/winter-navigation/": {"get": {"tags": ["public"], "summary": "Baltic winter navigation now (Finnish-Swedish icebreaker service, via Fintraffic Digitraffic)", "description": "Ports and fairways with an assistance restriction or suspension in force (now true) or announced; a\nrestriction such as \"IA 2000\" or \"IC 1300 / II 2000\" means icebreaker assistance only for ships of at least\nthat ice class and deadweight in tonnes; a suspension with closed true closes the port. Icebreakers with\nwhat each is doing (doing: LED lead, TOW tow, LOC local icebreaking, MOVE, TRANS, STOP, WAIT, OUT, CREWA,\nCREWP, ORDER), the ships planned next (queue) and the latest AIS position; ships waiting for assistance;\ndirways, the routes icebreakers publish through the ice ([lat, lon] points). Out of season the lists are\nempty and active is false. Fetched by the site every 10 minutes; licence CC BY 4.0, show credit.\nCache-Control public, max-age=60.\n", "security": [], "responses": {"200": {"description": "{ports: [{name, kind, country, locodes, winterport, lat, lon, port_slug, closed_now,\nrestrictions: [{text, start, end, now}], suspensions: [{start, end, now, closed, due, due_text, spec,\nprenotified}]}], icebreakers: [{name, imo, mmsi, call_sign, short, doing, activities: [{type, text, start,\nend, now, assisted, assisting, reason, comment}], queue: [{position, start, end, assisted, assisting}],\nlat, lon, sog, cog, hdg, position_at}], waiting: [{name, imo, mmsi, since}],\ndirways: [{name, description, points}], active, updated_at, available, credit, credits, source,\nsource_url, note}\n"}}}}, "/api/public/api-connect/": {"get": {"tags": ["public"], "summary": "Ready connections for editors, agents, programs and tools, with YOUR_KEY in place of the key", "description": "Editor install links (Cursor, VS Code), agent commands and config files, importable n8n and Node-RED flows,\na Home Assistant sensor, Power Query for Excel and Power BI, Apps Script for Google Sheets, code, a block for\nany ERP and the GitHub route-check workflow. Without `system` every system is listed.\nSystems: cursor, vscode, vscode_insiders, claude_code, claude_desktop, windsurf, zed, chatgpt_gpt, openai_tools, curl, python, javascript, powershell, excel_powerquery, power_bi, google_sheets, zapier, make, n8n, node_red, home_assistant, erp_generic, github_action.\n", "security": [], "parameters": [{"name": "system", "in": "query", "schema": {"type": "string"}, "description": "One system; omit for all"}, {"name": "path", "in": "query", "schema": {"type": "string"}, "description": "Where sealagom_mcp.py is on your computer (editor links)"}], "responses": {"200": {"description": "{systems: [{system, title, group, kind, body, note, href?, filename?, download_url?}], groups, openapi, mcp_file, mcp_path, key_filled}"}, "400": {"description": "Unknown system"}}}}, "/api/next-auth/api-connect/{token_id}/": {"get": {"tags": ["public"], "summary": "The same connections with your own key filled in (signed-in session on sealagom.com, not the API key)", "security": [], "parameters": [{"name": "token_id", "in": "path", "required": true, "schema": {"type": "integer"}}, {"name": "system", "in": "query", "schema": {"type": "string"}}, {"name": "path", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "As /api/public/api-connect/", "key_filled true": null, "never cached": null}, "401": {"description": "Not signed in"}, "404": {"description": "Not one of your active keys"}}}}, "/api/next-auth/github-connection/": {"get": {"tags": ["public"], "summary": "Connect GitHub status (signed-in session). GET /auth/github/connect/?token_id= creates the route-check repository", "security": [], "responses": {"200": {"description": "{enabled, authenticated, template, connection: {login, repo, url, last_run_url} or null, message}"}}}}, "/api/v2/fleet/positions/": {"post": {"tags": ["fleet"], "summary": "Push positions of your own vessels (a tracker, satellite AIS, the bridge); they show live in your sky and map only", "description": "One position, a list, or {\"positions\": [...]}, at most 500 a request. A vessel is found by vessel_id (our id,\nor your own id for her), mmsi or imo, and added the first time with her name (the plan's number of vessels;\n3 on the free trial, within the vessels your plan holds on SeaLagom). Other spellings providers use are read too (latitude, lng, sog, cog, hdg, timestamp,\na GeoJSON Point). Refused with a plain reason each: no vessel named, a position out of range or 0, 0, no time,\nolder than 24 hours or more than 5 minutes ahead, a speed over 80 knots, an impossible jump from the last\nposition (over 60 knots), a second position within 10 seconds of the last, or one older than it. At most 120\nrequests a minute per account (pushes, reads of your vessels and route changes together) and a number of\npositions a day by the access, counting the positions kept (429 with Retry-After). These calls never use the\nrequests of a data plan. Who may use it: the plans that include fleets (Fleet, Complete,\nFleet Pro, the Fleet unlimited license), company licences, and a 7 day free trial for people\n(POST /api/v2/fleet/trial/). Private by default; public only as a paid placement labelled Sponsored.\nNot for navigation.\n", "requestBody": {"content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/FleetPosition"}, {"type": "array", "items": {"$ref": "#/components/schemas/FleetPosition"}, "maxItems": 500}, {"type": "object", "required": ["positions"], "properties": {"positions": {"type": "array", "items": {"$ref": "#/components/schemas/FleetPosition"}, "maxItems": 500}}}]}}}}, "responses": {"200": {"description": "Some or all kept", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FleetPushResult"}}}}, "400": {"description": "No position in the body"}, "401": {"description": "No key, a wrong key, or the key of a deactivated account"}, "402": {"description": "A paused licence case lists this key or account: what to do, the links and the support contact"}, "403": {"description": "No fleet access on this account: why (trial_available, trial_used, verify_email), plans and docs links"}, "422": {"description": "Every position refused", "with the reasons": null, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FleetPushResult"}}}}, "429": {"description": "Over the requests a minute or the positions a day (Retry-After)"}}}}, "/api/v2/fleet/vessels/": {"get": {"tags": ["fleet"], "summary": "Your vessels with status, last position and age, speed, course, ETA, warnings near and along the route, approximate under-keel clearance", "description": "Without access of your own (the trial over, no plan) only the vessels shared with you are listed.", "parameters": [{"name": "detail", "in": "query", "schema": {"type": "boolean"}, "description": "every warning", "not the first 5": null}], "responses": {"200": {"description": "{access, count, vessels: [FleetVessel], note}", "content": {"application/json": {"schema": {"type": "object", "properties": {"count": {"type": "integer"}, "vessels": {"type": "array", "items": {"$ref": "#/components/schemas/FleetVessel"}}}}}}}, "429": {"description": "Over the requests a minute (Retry-After)"}}}}, "/api/v2/fleet/vessels/{vessel}/": {"get": {"tags": ["fleet"], "summary": "One vessel in full, with her last 24 hours of track and a link to see her in the sky", "parameters": [{"name": "vessel", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Our id, MMSI, IMO, your own id or her name"}], "responses": {"200": {"description": "The vessel", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FleetVessel"}}}}, "403": {"description": "Your own vessel while the account has no fleet access (why, plans and docs links); a vessel shared with you stays readable"}, "404": {"description": "Not a vessel of this account"}, "429": {"description": "Over the requests a minute (Retry-After)"}}}}, "/api/v2/fleet/vessels/{vessel}/route/": {"put": {"tags": ["fleet"], "summary": "Set her route for the ETA and the warnings along it (POST works the same)", "parameters": [{"name": "vessel", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object", "required": ["waypoints"], "properties": {"waypoints": {"type": "array", "minItems": 2, "maxItems": 500, "description": "One voyage, at most 13,000 nm long", "items": {"oneOf": [{"type": "array", "items": {"type": "number"}, "minItems": 2, "maxItems": 2}, {"type": "object", "properties": {"lat": {"type": "number"}, "lon": {"type": "number"}}}]}}, "speed_kn": {"type": "number", "description": "The planned speed", "used for the ETA while she reports none": null}, "name": {"type": "string"}, "destination": {"type": "string"}}}}}}, "responses": {"200": {"description": "{ok, route, vessel}"}, "400": {"description": "Fewer than two waypoints, a speed out of range, or a route over 13,000 nm (why route_too_long)"}, "403": {"description": "Only her owner and editors set her route, with fleet access (her owner's for a vessel shared with you)"}, "429": {"description": "Over the requests a minute (Retry-After)"}}}, "delete": {"tags": ["fleet"], "summary": "Clear her route", "parameters": [{"name": "vessel", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "{ok, route: cleared}"}}}}, "/api/v2/fleet/webhook/": {"get": {"tags": ["fleet"], "summary": "Your webhook receiver for providers that push, and how to sign (never the secret)", "responses": {"200": {"description": "{url, secret_hint, signing: {header, value, also, tolerance_s}, last_push_at, last_status, last_refused: {at, why} or null (the last push refused for its signature, kept a day)}"}}}, "post": {"tags": ["fleet"], "summary": "A new signing secret with {\"rotate\": true}, shown once in this answer", "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"rotate": {"type": "boolean"}}}}}}, "responses": {"200": {"description": "{url, secret, secret_note, signing}"}}}}, "/api/v2/fleet/access/": {"get": {"tags": ["fleet"], "summary": "What this account may do: via plan, licence, trial or staff, vessels, positions a day, the limits", "responses": {"200": {"description": "{ok, via, vessels, per_day, trial, why, in_feed, limits}"}}}}, "/api/v2/fleet/trial/": {"post": {"tags": ["fleet"], "summary": "Start the free trial for people (7 days, 3 vessels, once per account, a verified e-mail)", "responses": {"201": {"description": "{ok, access}"}, "403": {"description": "Verify the e-mail first"}, "409": {"description": "The account has the feed already", "or the trial was used": null}}}}, "/api/fleet/hook/{token}/": {"post": {"tags": ["fleet"], "summary": "The webhook receiver of one account (its address is on GET /api/v2/fleet/webhook/)", "description": "Any JSON the provider sends: our position format, a list, an envelope (data, items, records, vessels...) or a\nGeoJSON FeatureCollection of Points. Sign each push: X-SeaLagom-Signature: t=<unix seconds>,v1=<hex\nHMAC-SHA256 of \"<t>.<raw body>\" with your secret> (within 5 minutes of our clock), or X-Hub-Signature-256:\nsha256=<hex HMAC-SHA256 of the raw body>. ?provider= names the source (kept with the positions). A signed push\nis taken once: the same signature again answers 200 with duplicate true and keeps nothing (a push refused\nwhole is not remembered, so a retry goes through).\n", "security": [], "parameters": [{"name": "token", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "X-SeaLagom-Signature", "in": "header", "schema": {"type": "string"}}, {"name": "provider", "in": "query", "schema": {"type": "string", "maxLength": 40}}], "requestBody": {"content": {"application/json": {"schema": {"type": "object"}}}}, "responses": {"200": {"description": "The same answer as POST /api/v2/fleet/positions/, or {duplicate: true} for a push taken before"}, "401": {"description": "No signature or a wrong one"}, "402": {"description": "A paused licence case lists this account"}, "404": {"description": "Unknown address"}, "429": {"description": "Over the limits, or over 30 unsigned or wrongly signed pushes a minute (Retry-After)"}}}}, "/mcp/fleet": {"post": {"tags": ["fleet"], "summary": "The fleet feed as an MCP server for agents (JSON-RPC 2.0, streamable HTTP, JSON answers): tools fleet_access, fleet_vessels, fleet_vessel, fleet_push_positions, fleet_set_route, fleet_start_trial", "requestBody": {"content": {"application/json": {"schema": {"type": "object", "properties": {"jsonrpc": {"type": "string"}, "id": {}, "method": {"type": "string"}, "params": {"type": "object"}}}}}}, "responses": {"200": {"description": "The JSON-RPC answer"}, "402": {"description": "A paused licence case lists this key or account"}}}}}, "components": {"securitySchemes": {"apiToken": {"type": "apiKey", "in": "header", "name": "X-API-Token"}, "bearerAuth": {"type": "http", "scheme": "bearer", "description": "The same API key as a Bearer token."}}, "schemas": {"WarningPage": {"type": "object", "properties": {"count": {"type": "integer", "description": "Warnings matching the request", "all pages": null}, "page": {"type": "integer"}, "page_size": {"type": "integer"}, "next": {"type": ["string", "null"], "format": "uri"}, "previous": {"type": ["string", "null"], "format": "uri"}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/Warning"}}, "meta": {"type": "object", "properties": {"warnings": {"type": "array", "items": {"type": "string"}, "description": "Features left out for the plan", "ignored filters": null}, "prompt_filter": {"type": "object"}, "topic": {"type": "object"}}}}}, "Warning": {"$ref": "./models/warning.schema.json"}, "Analysis": {"$ref": "./models/analysis.schema.json"}, "RouteRequest": {"type": "object", "required": ["waypoints"], "properties": {"waypoints": {"type": "array", "minItems": 2, "items": {"type": "object", "required": ["lat", "lon"], "properties": {"lat": {"type": "number", "minimum": -90, "maximum": 90}, "lon": {"type": "number", "minimum": -180, "maximum": 180}}}}, "speed_kn": {"type": "number", "default": 12}, "corridor_nm": {"type": "number", "default": 10}, "departure": {"type": "string", "format": "date-time", "description": "UTC; default now"}}}, "RouteResult": {"$ref": "./models/route-result.schema.json"}, "Region": {"type": "object", "properties": {"id": {"type": "integer"}, "title": {"type": "string"}, "sub_title": {"type": "string", "description": "Coastal regions only"}, "country": {"type": "string"}, "time_upd": {"type": "string", "format": "date-time"}, "active_messages": {"type": "array", "items": {"$ref": "#/components/schemas/Warning"}}, "archived_messages": {"type": "array", "items": {"$ref": "#/components/schemas/Warning"}}}}, "RegionPage": {"type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": ["string", "null"]}, "previous": {"type": ["string", "null"]}, "results": {"type": "array", "items": {"$ref": "#/components/schemas/Region"}}}}, "FleetPosition": {"type": "object", "required": ["lat", "lon", "time"], "properties": {"vessel_id": {"type": "string", "description": "Our vessel id or your own id for her"}, "mmsi": {"type": "string", "pattern": "^[0-9]{9}$"}, "imo": {"type": "string", "pattern": "^[0-9]{7}$"}, "name": {"type": "string"}, "lat": {"type": "number", "minimum": -90, "maximum": 90}, "lon": {"type": "number", "minimum": -180, "maximum": 180}, "time": {"type": ["string", "integer"], "description": "ISO 8601 in UTC or Unix seconds"}, "speed": {"type": "number", "description": "knots over ground"}, "course": {"type": "number", "description": "degrees true over ground"}, "heading": {"type": "number"}, "draught": {"type": "number", "description": "metres", "as reported": null}, "length": {"type": "number", "description": "metres"}, "beam": {"type": "number", "description": "metres"}, "destination": {"type": "string"}, "nav_status": {"type": "integer", "description": "AIS navigational status"}}}, "FleetPushResult": {"type": "object", "properties": {"accepted": {"type": "integer"}, "refused": {"type": "array", "items": {"type": "object", "properties": {"index": {"type": "integer"}, "why": {"type": "string"}}}}, "refused_count": {"type": "integer"}, "vessels": {"type": "array", "items": {"type": "object", "properties": {"vessel_id": {"type": "string"}, "name": {"type": "string"}, "accepted": {"type": "integer"}, "last_time": {"type": "string"}}}}, "note": {"type": "string"}}}, "FleetVessel": {"type": "object", "properties": {"vessel_id": {"type": "string", "format": "uuid"}, "ref": {"type": "string"}, "name": {"type": "string"}, "mmsi": {"type": ["string", "null"]}, "imo": {"type": ["string", "null"]}, "kind": {"type": "string"}, "length_m": {"type": ["number", "null"]}, "beam_m": {"type": ["number", "null"]}, "shared": {"type": "boolean", "description": "true when the vessel is another account's", "shared with you": null}, "status": {"type": "string", "enum": ["moving", "at_anchor", "no_update", "unknown", "no_position"]}, "position": {"type": "object", "properties": {"lat": {"type": "number"}, "lon": {"type": "number"}, "time": {"type": "string"}, "age_s": {"type": "integer"}, "source": {"type": "string"}, "provider": {"type": ["string", "null"]}}}, "speed_kn": {"type": ["number", "null"]}, "course": {"type": ["number", "null"]}, "heading": {"type": ["number", "null"]}, "draught_m": {"type": ["number", "null"]}, "motion_derived": {"type": "boolean", "description": "speed or course worked out from her last two positions"}, "destination": {"type": ["string", "null"]}, "route": {"type": ["object", "null"], "description": "name, total_nm, remaining_nm, off_route_nm, next_waypoint, eta, eta_speed_kn, eta_speed_from (reported or planned)"}, "warnings_near": {"type": "object", "description": "radius_nm, count, items [{id, title, headline, url, distance_nm, lat, lon}]"}, "warnings_route": {"type": ["object", "null"], "description": "corridor_nm, count, items [{id, title, headline, url, distance_nm, along_nm, eta}]"}, "clearance": {"type": "object", "description": "available, depth_m, draught_m, squat_m, clearance_m, band (ample, tight, very_tight), estimate, caveats: an estimate from GEBCO, never a safety value"}, "track": {"type": "array", "description": "The last 24 hours (one vessel only)"}, "sky_url": {"type": ["string", "null"]}, "note": {"type": "string"}}}}}}