API Reference
REST API
The OpenDiveMap API serves dive site data as GeoJSON over HTTP, following the
OGC API - Features
response conventions.
All responses use Content-Type: application/json.
No authentication is required for read endpoints.
Base URL
https://api.opendivemap.com/v1 All endpoints are served under the /v1 prefix. Unversioned paths redirect to /v1 for backward compatibility.
Units
All measurements are always returned in SI / metric, following
international diving standards (PADI, SSI) and the same convention used by OpenStreetMap, NOAA, and GBIF.
Field names encode the unit: max_depth_m (meters),
visibility_avg_m (meters).
The API schema is fixed — field names and units never change. If your application needs imperial display,
convert client-side: meters × 3.28084 = feet.
Error format
All error responses use a consistent JSON structure with a machine-readable
code, a human-readable
message, and optional
details for field-level validation errors.
{
"code": "INVALID_PARAMETER",
"message": "Human-readable description of what went wrong",
"details": [
{ "field": "topology", "reason": "Got \"invalid_value\"" }
]
} INVALID_PARAMETER 400 A query parameter has an invalid value.
NOT_FOUND 404 The requested resource does not exist.
INTERNAL_ERROR 500 Unexpected server failure.
Pagination
The GET /sites endpoint supports pagination
following the OGC API - Features convention. The response includes:
numberMatched — total features matching the filters (before pagination)
numberReturned — features in this page
links — array with self,
next, and prev navigation URLs
Use ?limit= (default 100, max 1000) and
?offset= (default 0) to paginate.
When there are more results, a next link is included.
GET /enums
Returns all accepted values for environment,
topology, and level
with human-readable labels and descriptions. Use this to populate filter dropdowns,
validate input, or display classification info in your UI.
Example request
curl "https://api.opendivemap.com/v1/enums" Response
{
"environments": [
{ "value": "ocean", "label": "Ocean", "description": "Open ocean and sea dives" },
{ "value": "lake", "label": "Lake", "description": "Freshwater lake dives" },
...
],
"topologies": [
{ "value": "reef", "label": "Reef", "description": "Coral reef or rocky reef" },
{ "value": "wall", "label": "Wall", "description": "Vertical walls and drop-offs" },
...
],
"levels": [
{ "value": "beginner", "label": "Beginner", "description": "Open Water or equivalent" },
{ "value": "intermediate", "label": "Intermediate", "description": "Advanced Open Water or equivalent" },
{ "value": "advanced", "label": "Advanced", "description": "Deep / technical certifications" }
]
} GET /stats
Returns aggregate counts for the entire dataset. Use this for dashboards, badges, or homepage stats instead of fetching all sites.
Example request
curl "https://api.opendivemap.com/v1/stats" Response
{
"total_sites": 4,
"total_countries": 3,
"by_level": {
"beginner": 1,
"intermediate": 1,
"advanced": 2
},
"by_environment": {
"ocean": 4
},
"by_topology": {
"pinnacle": 1,
"cave": 1,
"blue_hole": 1,
"reef": 1,
"wreck": 1
}
} GET /sites
Returns dive sites as a GeoJSON FeatureCollection with OGC pagination metadata.
Parameters
country string optional Filter by ISO 3166-1 alpha-2 country code. E.g. ?country=MX
level string optional Filter by difficulty. One of: beginner, intermediate, advanced.
environment string optional Filter by environment. One of: ocean, lake, river, spring, quarry, fjord, pool.
topology string optional Filter by topology. Returns sites that have the given topology. One of: reef, wall, pinnacle, wreck, cave, cavern, blue_hole, muck, kelp_forest, channel, artificial_reef, open_water.
bbox string optional Bounding box filter. Format: west,south,east,north (decimal degrees).
limit integer optional Maximum number of features per page. Default: 100. Max: 1000.
offset integer optional Number of features to skip. Default: 0.
Example request
curl "https://api.opendivemap.com/v1/sites?country=MX&level=advanced&limit=10" Response
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-110.3981, 24.2156]
},
"properties": {
"id": "dccaf1e1-5df6-4058-a10c-00cdc85e87fb",
"name": "El Bajo Seamount",
"country_code": "MX",
"environment": "ocean",
"topologies": ["pinnacle"],
"max_depth_m": 40,
"level": "advanced",
"tags": {
"wildlife": ["hammerhead_shark", "manta_ray"],
"current": "strong",
"entry": "boat"
}
}
}
],
"numberMatched": 2,
"numberReturned": 1,
"links": [
{
"rel": "self",
"href": "https://api.opendivemap.com/v1/sites?country=MX&level=advanced&limit=1",
"type": "application/geo+json"
},
{
"rel": "next",
"href": "https://api.opendivemap.com/v1/sites?country=MX&level=advanced&limit=1&offset=1",
"type": "application/geo+json"
}
]
} GET /sites/:id
Returns a single dive site as a GeoJSON Feature. Includes created_at and
updated_at timestamps in the properties.
Path parameters
id UUID required The dive site UUID.
Example request
curl "https://api.opendivemap.com/v1/sites/dccaf1e1-5df6-4058-a10c-00cdc85e87fb" Response
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-110.3981, 24.2156]
},
"properties": {
"id": "dccaf1e1-5df6-4058-a10c-00cdc85e87fb",
"name": "El Bajo Seamount",
"country_code": "MX",
"environment": "ocean",
"topologies": ["pinnacle"],
"max_depth_m": 40,
"level": "advanced",
"tags": { ... },
"created_at": "2026-02-22T03:02:19.013216+00:00",
"updated_at": "2026-02-22T03:02:30.255437+00:00"
}
} GET /sites/:id/history
Returns an array of previous versions of the dive site, ordered by most recent change first. Each entry contains the full row snapshot at the time of the change.
Path parameters
id UUID required The dive site UUID.
Example request
curl "https://api.opendivemap.com/v1/sites/dccaf1e1-5df6-4058-a10c-00cdc85e87fb/history" Response
[
{
"data": {
"id": "dccaf1e1-5df6-4058-a10c-00cdc85e87fb",
"name": "El Bajo Seamount",
"max_depth_m": 40,
"level": "advanced",
...
},
"changed_at": "2026-02-22T03:02:30.255437+00:00"
}
]