Docs

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 views
  • GET/POST/DELETE /api/drawings — saved drawings
  • GET/POST/PUT/DELETE /api/alerts — alert regions
  • GET/POST/DELETE /api/prompts/ — saved AI prompts
  • POST /api/prompts/<id>/used — bump usage counter

Billing

  • POST /api/billing/checkout — Stripe checkout session
  • POST /api/billing/portal — customer portal
  • POST /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.