geoprimitives
GET api.geoprimitives.dev/v1/marine/hazards
Why an agent can trust this route.
Sonar evidence is advisory. Paid delivery is shown as verified only when paid probes are available; otherwise route estimates use the unpaid handshake as a clearly labeled proxy.
Observed outcomes
Give it a latitude, a longitude and a radius in metres and it answers with every charted underwater rock, obstruction and wreck inside that circle, nearest first, each with its charted depth, its water level effect, its name where the chart names it, and the geodesic distance from your position. Parameters go in the query string: this is a GET, there is no body. NOT FOR NAVIGATION, stated first because it is a condition of using the source. Derived from NOAA Electronic Navigational Charts and redistributed; not an official NOAA ENC, and it does not meet federal chart carriage regulations under 33 CFR 164 or SOLAS chapter V. Every response repeats this under `disclaimer`. NOAA and NOAA ENC are registered trademarks of NOAA, which does not endorse this service. COVERAGE is the same 65 cells as GET /v1/marine/depth: bands 3 to 5 over Sitka Sound; Kasaan Bay and Clarence Strait; Metlakatla, Ketchikan and Revillagigedo Channel; Juneau, Gastineau Channel and Lynn Canal; and Cordova with eastern Prince William Sound. Not statewide and not the whole coast. The check reads the coordinate, so it happens after payment; a position off the charts is refused with outside_coverage, which does not settle. Every response repeats the coverage under `coverage`. WHAT AN EMPTY ANSWER MEANS, because this is the one that can hurt: an empty list means the chart shows nothing there, not that the water is clear. Read the zone of confidence from GET /v1/marine/depth for the same position before you read anything into a clean result. Zones C, D and U mean the area was never fully searched and NOAA says so; in zone D large depth anomalies may be expected. Only three S-57 classes are searched -- UWTROC, OBSTRN and WRECKS -- so a charted danger that is a buoy, a cable, a fish haven area, a spoil ground or a restricted area is not in this store and will not appear. WHICH CHART ANSWERS, and why it is not just one: the largest-scale cell covering each part of the search wins, applied per location rather than once for the whole circle. A harbour cell ends at its own edge and the water a kilometre outside it is charted by the approach cell, so a search that fixed on one chart would drop those hazards silently. `cellsSearched` lists every cell that contributed, and each hazard names the cell it came from. Where two cells chart the same rock at a seam it is returned once. DEPTHS are metres below Mean Lower Low Water. A null depth is a hazard the chart gives no sounding for; read `waterLevel` instead, since an object that covers and uncovers, or is awash, has no single depth. `chartedAsArea` marks a wreck or obstruction the chart carries as an area rather than a point, in which case the position given is its centroid and the thing itself is larger. LIMITS: the radius runs from 1 to 5000 metres and defaults to 1000. A search may read 100 chart tiles, counted from the geometry before any read, so an over-wide request is refused for free rather than part-served; the widest legal radius needs at most 81, so the radius is the limit you meet and the tile count is a backstop. At most 200 hazards come back, nearest first, and the response says when it truncated. VINTAGE is a 2026-05-02 snapshot of charts NOAA reissues weekly; the cell edition and issue date that answered are in each hazard's cell and in `source`. For how deep the water is rather than what is in it, use GET /v1/marine/depth.
Resource: api.geoprimitives.dev/v1/marine/hazards
Network: eip155:8453 · Asset: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 · Pay to: 0x76A51b5Dd3729950B3b60c17f19252d221968FCe
Payment methods: — · Last validation: 2026-10-15 11:53:37.134+00
{
"input": {
"type": "object",
"required": [
"type",
"method"
],
"properties": {
"type": {
"type": "string",
"const": "http"
},
"method": {
"enum": [
"GET"
],
"type": "string"
},
"queryParams": {
"type": "object",
"required": [
"lat",
"lon"
],
"properties": {
"lat": {
"type": "number",
"maximum": 90,
"minimum": -90,
"description": "Latitude in decimal degrees, EPSG:4326. Refused outside -90..90."
},
"lon": {
"type": "number",
"maximum": 180,
"minimum": -180,
"description": "Longitude in decimal degrees, EPSG:4326. Refused outside -180..180."
},
"radiusMetres": {
"type": "number",
"default": 1000,
"maximum": 5000,
"minimum": 1,
"description": "Search radius in metres, 1 to 5000. Omit for 1000. A wider search is refused rather than truncated silently."
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"output": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string"
},
"example": {
"type": "object"
}
}
},
"paymentRequirements": [
{
"raw": {
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"extra": {
"name": "USD Coin",
"version": "2"
},
"payTo": "0x76A51b5Dd3729950B3b60c17f19252d221968FCe",
"amount": "5000",
"scheme": "exact",
"network": "eip155:8453",
"maxTimeoutSeconds": 300
},
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x76A51b5Dd3729950B3b60c17f19252d221968FCe",
"scheme": "exact",
"network": "eip155:8453",
"amountAtomic": "5000"
}
]
}Source catalog records are retained separately from live endpoint observations. Sonar score, uptime, and latency are advisory metrics. CDP indexing is not inferred from validation.