API reference
Every REST endpoint in NTHMAP with query parameters and response shapes.
The NTHMAP API is REST + JSON. Every endpoint accepts either a session cookie (if you're signed into the web app) or an Authorization: Bearer <api-key> header. API keys are available on the Pro tier and above.
Base URL: https://nthmap.com/api
All responses are JSON. All timestamps are ISO 8601 UTC. All coordinates are WGS-84 [lng, lat] unless otherwise noted.
Authentication
Authorization: Bearer ntm_live_9xY2m8qR...
Or session cookie (from browser login):
Cookie: nthmap_session=...
Unauthenticated requests get:
- Free-tier responses for /api/vessels, /api/infrastructure, /api/prices (WTI/Brent/NG only)
- 401 Unauthorized for authenticated endpoints
- 402 Payment Required with {"upgrade": true} for Pro-gated endpoints
Vessels
GET /api/vessels
List vessels, filtered by viewport + type + speed/load.
Query parameters:
| Param | Type | Description |
|---|---|---|
bbox |
minLng,minLat,maxLng,maxLat |
Restrict to viewport |
types |
comma-separated | Crude Tanker,LNG Carrier,LPG Carrier,Chemical Tanker,Bulk Carrier,Container Ship |
min_speed / max_speed |
float (knots) | Speed range filter |
min_load / max_load |
float (%) | Load percentage filter |
commodity |
string | e.g. Crude Oil |
zoom |
float | Used for zoom-aware result capping |
Zoom-aware cap: if zoom < 3 → up to 200 vessels, 3–5 → 800, 5–7 → 1500, 7+ → 5000. The cap always keeps the largest vessels by est_cargo_mt, so a world-view query shows the biggest VLCCs first.
Response: array of vessel objects.
[
{
"mmsi": "311000001",
"name": "GULF NAVIGATOR",
"vessel_type_str": "Crude Tanker",
"commodity": "Crude Oil",
"flag": "MH",
"dwt": 300000,
"max_draught_m": 20.5,
"current_draught_m": 19.2,
"lat": 26.5,
"lng": 56.3,
"speed_knots": 12.4,
"heading": 245,
"nav_status": 0,
"destination": "NLRTM",
"eta": "2026-04-28T12:00:00Z",
"last_port": "Ras Tanura",
"last_port_country": "Saudi Arabia",
"load_pct": 93,
"est_cargo_mt": 279000
}
]
GET /api/vessels/<mmsi>
Full detail for one vessel.
GET /api/vessels/<mmsi>/track Pro
Last 24 hours of positions for that vessel. Returns up to 500 points ordered newest first.
Infrastructure
GET /api/infrastructure
| Param | Description |
|---|---|
bbox |
Restrict to viewport |
types |
lng_terminal,oil_refinery,oil_pipeline,gas_pipeline,port,coal_mine,oil_field,spr |
commodity |
e.g. crude, lng |
Pipelines include a route_geojson LineString for rendering the full route.
Events Pro
GET /api/events
| Param | Description |
|---|---|
bbox |
Restrict to viewport |
types |
hurricane,earthquake,wildfire,conflict,sanctions,port_closure |
active |
true (default) |
Response includes radius_km for circle rendering.
Chokepoints Pro
GET /api/chokepoints
All 8 strategic chokepoints with live vessel counts, average speed, and status.
Prices
GET /api/prices
Latest price for every commodity. Free tier sees WTI, Brent, Natural Gas. Pro sees all 12.
GET /api/prices/history/<symbol> Pro
Last 30 days of prices for a symbol.
Flows Pro
GET /api/flows
The arbitrage panel. Aggregate inbound vessels + estimated cargo + average ETA for a destination region.
| Param | Description |
|---|---|
destination_region |
Europe,Asia,North America,Middle East,South America,Africa |
commodity |
e.g. Crude Oil |
Returns:
{
"region": "Europe",
"commodity": "Crude Oil",
"vessels_inbound": 37,
"est_cargo_mt": 8712000,
"avg_eta_days": 9.2
}
Draw analysis
POST /api/draw/analyze
The single most valuable endpoint. Give it a GeoJSON polygon, get back a full regional snapshot: vessels inside, commodity breakdown, infrastructure, active events.
Body:
{
"geojson": {
"type": "Polygon",
"coordinates": [[[54,25],[58.5,25],[58.5,27.5],[54,27.5],[54,25]]]
},
"draw_type": "polygon"
}
Response:
{
"total_vessels": 47,
"vessels_inside": [...],
"commodity_breakdown": {
"Crude Tanker": 22,
"LNG Carrier": 8,
"Chemical Tanker": 6,
"Bulk Carrier": 7,
"LPG Carrier": 4
},
"est_cargo_mt": 2054785,
"events_inside": [...],
"infrastructure_inside": [...],
"ai_available": true
}
AI Pro
POST /api/ai/vessel-context
Generate a three-sentence trading context summary for a specific vessel.
{ "mmsi": "311000001" }
POST /api/ai/query
Convert a natural-language query into filter parameters.
{ "q": "LNG carriers near Hormuz over 90% loaded" }
Returns { "filters": { ... }, "explanation": "..." }.
POST /api/ai/flow-analysis
Narrative analysis of a region's vessel flows.
{ "bbox": [54, 25, 58.5, 27.5], "commodity": "Crude Oil" }
User features
All require authentication.
GET/POST/DELETE /api/views— saved viewsGET/POST/DELETE /api/drawings— saved drawingsGET/POST/PUT/DELETE /api/alerts— alert regionsGET/POST/DELETE /api/prompts/— saved AI promptsPOST /api/prompts/<id>/used— bump usage counter
Billing
POST /api/billing/checkout— Stripe checkout sessionPOST /api/billing/portal— customer portalPOST /api/billing/webhook— Stripe webhook handler (don't call)
Rate limits
Free tier: 60 requests/minute Pro: 300 requests/minute Enterprise: negotiated
Exceeded requests get 429 Too Many Requests with a Retry-After header.
Error responses
All errors follow the same shape:
{ "error": "description of what went wrong" }
Pro-gated endpoints add an "upgrade": true flag so your client can route to the upgrade flow.