Elevation API

One endpoint: send it a single coordinate or up to a thousand, and it answers with ground elevation in metres above CGVD2013 for every one of them.

Every request needs an API key; see Authentication.

live result
the code that produced it
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.0719, 51.0447],
  zoom: 11,
});

const [metres] = await unmap.elevation.get([-114.0719, 51.0447]);

unmap.map!.on("click", async (e) => {
  const [here] = await unmap.elevation.get([e.lngLat.lng, e.lngLat.lat]);
  console.log(here === null ? "no data here" : `${here} m`);
});
npm i @unmap/elevation

@unmap/elevation is the standalone client; @unmap/sdk exposes the same object as unmap.elevation. Everything below is the HTTP contract underneath both.

Elevation

GET /elevation
  • lon, lat (required, unless points is given): a single coordinate.
  • points (required, unless lon/lat are given): several coordinates in one request, |-separated lon,lat pairs, e.g. -114.0719,51.0447|-115.5708,51.1784. Up to 1000 coordinates. Passing points alongside lon/lat is a 400.

A batch is bounded by the request URL as well as by the coordinate count. A URL is limited to 16 KB, and the separators are percent-encoded on the wire, so roughly 700 coordinates at six decimal places fit before the URL runs out: in practice that ceiling arrives before the 1000 cap does. Past it the request is refused at the edge with a 414, before the gateway sees it, so there is no error envelope to read. @unmap/elevation checks the URL it built and throws first, naming how many of your coordinates fit.

One request is one billed call whether it carries a single coordinate or all 1000, the same rule /route and /isochrone follow: batching coordinates into one request costs nothing extra over asking for them one at a time.

curl "https://api.unmap.dev/elevation?lon=-114.0719&lat=51.0447&key=YOUR_KEY"
{ "elevations": [1046.9], "units": "m", "datum": "CGVD2013", "resolution": 30 }
  • elevations: one entry per coordinate, in the order you asked, in metres, rounded to the nearest tenth. An entry is null where the archive has no data there; see "What null means" below.
  • units: always "m".
  • datum: "CGVD2013", the vertical datum every value is measured against.
  • resolution: 30, the source DEM's nominal cell size in metres. This describes the ground truth, not the query: samples are read from a finer, bilinearly interpolated surface, so resolution is not the spacing between the points you can ask about.

A malformed lon, lat, or entry inside points is a 400 naming the value at fault. More than 1000 coordinates in points is a 400 too.

What null means

null in elevations means the archive covers nothing at that coordinate. It never means sea level, and the client does not substitute a number for a hole in the data. Check for null before doing arithmetic on a result, the same way you would check for a missing field from any other API: a silent zero there would read as a real measurement at the coast, which is exactly the wrong place to be wrong.

The dataset

Elevations come from NRCan's MRDEM-30, part of the CanElevation series. It is a terrain model (a DTM): it describes the ground, not tree canopy or rooftops. Cells are 30 m nominal, in source CRS EPSG:3979, on the CGVD2013 vertical datum, so a value is a height above the geoid, not an ellipsoidal height.

MRDEM-30 is built from Copernicus GLO-30, void-filled, with NRCan's own HRDEM lidar blended in wherever it exists. /elevation samples that surface bilinearly from the four surrounding cells, rather than snapping to the nearest one.

The data is licensed under the Open Government Licence - Canada (OGL-Canada). A Copernicus WorldDEM-30 notice is reproduced at unmap.dev/attribution.

Coverage and its edge

Coverage is Canada, plus the watershed spill across the US border that the source itself carries; it reaches 85°N.

Past 85.05°N and 85.05°S, where the web mercator grid the archive is tiled on ends, the answer is null rather than the value at the nearest latitude it can sample.

Within roughly one tile of the coverage edge, along coasts, the US border and the mouths of fjords, values are extrapolated from the nearest real cell rather than measured, because the same dataset renders the hillshade and a hard edge there would draw as a cliff. Treat elevations within about 10 km of open water as indicative.

Limits and billing

One request is one call, whether it carries a single coordinate or a full batch of 1000 (or the roughly 700 the 16 KB URL limit leaves room for, whichever you reach first). There is no add-on: elevation is available on every plan, at the same per-call rate as the rest of the gateway.

See Errors for the shared error envelope.