Skip to content

Check 3DEP lidar coverage

You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.

GET /domains/{domain_id}/pointclouds/3dep/coverage answers four questions about a domain before you spend anything on it: is there public lidar here, whose is it, how dense is it, and will a fetch fit the budget?

It is a catalog lookup and some geometry — no point data is read — so it returns immediately. Every failure mode of fetching a 3DEP point cloud is visible here first, which is the reason to run it.

  1. An API key: my-api-key.

  2. A domain: your-domain-id. See Create a domain.

GET pointclouds/3dep/coverage
curl -X 'GET' \
'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/pointclouds/3dep/coverage' \
-H 'accept: application/json' \
-H 'api-key: my-api-key'
FieldWhat to do with it
availablefalse means a create request will be rejected. Stop here.
coverage_fractionThe share of the domain any 3DEP lidar covers, 0.01.0. See the caveat below.
estimated_point_countRoughly how many points a fetch would return.
point_budgetThe per-fetch ceiling — 200,000,000 points.
exceeds_point_budgettrue means a create request will be rejected. Shrink the domain.
datasets[]The acquisitions that would be read, in the order they would be used.

Each entry in datasets[] describes one USGS acquisition:

  • name — pass it back in datasets on the create request to pin the fetch to this acquisition.
  • contribution_fraction — the share of the domain this acquisition would supply. Acquisitions overlap freely, so this is what is left over after the ones listed before it have taken their part, not the raw overlap. The values are disjoint and sum to coverage_fraction.
  • estimated_density — average points per square metre over the acquisition’s full published extent.
  • estimated_points — derived from density and area, so treat it as an order of magnitude rather than a count.

Some parts of the country do not have 3DEP lidar data available. When that is the case the response is unambiguous and datasets is empty:

{
"available": false,
"coverage_fraction": 0.0,
"datasets": [],
"estimated_point_count": 0,
"point_budget": 200000000,
"exceeds_point_budget": false
}

A create request against this domain returns a 422. Your options are a different area, or a canopy source that does not need lidar — NAIP and Meta both produce a chm band without one, and neither has coverage gaps. See Choosing a source.

When no single survey covers the domain, the backend combines the fewest that fill it. Here two acquisitions are needed, and they are not equivalent — the first supplies 87.7% of the domain at 28.3 pts/m², the second the remaining 12.3% at 3.0 pts/m², an order of magnitude sparser:

{
"available": true,
"coverage_fraction": 1.0,
"datasets": [
{
"name": "AZ_MohaveCoconino_1_D23",
"url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/AZ_MohaveCoconino_1_D23/ept.json",
"contribution_fraction": 0.8773581560283717,
"estimated_density": 28.31556851085709,
"estimated_points": 9534173
},
{
"name": "AZ_MohaveCo_2_2021",
"url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/AZ_MohaveCo_2_2021/ept.json",
"contribution_fraction": 0.12264184397162811,
"estimated_density": 2.9543377555480443,
"estimated_points": 139052
}
],
"estimated_point_count": 9673225,
"point_budget": 200000000,
"exceeds_point_budget": false
}
Two horizontal bar charts. The left shows AZ_MohaveCoconino_1_D23 supplying 87.7 percent of the domain and AZ_MohaveCo_2_2021 supplying 12.3 percent. The right shows their estimated densities as 28.3 and 3.0 points per square metre respectively.

The same two acquisitions, by share of the domain and by density. The minority acquisition is nearly ten times sparser — read both panels, not just the first.

This is worth looking at rather than skipping past. A mosaic puts a seam between flights of different dates and densities through your data, and downstream products inherit it — a CHM built across this domain is detailed on one side of the seam and coarse on the other. If that matters, pin the better acquisition and accept partial coverage rather than taking both.

A single fetch is capped at 200 million points. Density and area together decide whether you are over it, so a small domain over dense lidar can exceed the budget as easily as a large one over sparse lidar:

{
"available": true,
"coverage_fraction": 1.0,
"datasets": [
{
"name": "MT_Statewide_P3_4_B21",
"url": "https://s3-us-west-2.amazonaws.com/usgs-lidar-public/MT_Statewide_P3_4_B21/ept.json",
"contribution_fraction": 1.0,
"estimated_density": 14.811981421134373,
"estimated_points": 227552496
}
],
"estimated_point_count": 227552496,
"point_budget": 200000000,
"exceeds_point_budget": true
}

Attempting the fetch anyway returns a 422 naming both numbers. Shrink the domain — note that domains are capped at 16 km² regardless — and check again.

  • Skipping the pre-flight and reading source.coverage_fraction afterwards. Both report the same number, but only one of them is free. A rejected create request costs a round trip; a fetch that succeeds with a hole in it costs a background job and everything you build on it.
  • Treating estimated_point_count as a count. It is derived from published density over published extent. In a verified run the estimate was 7,847,291 and the fetch returned 10,512,255 — within an order of magnitude, not within a rounding error.
  • Assuming a covered domain is a uniformly covered domain. Read datasets[].estimated_density before you assume the far corner is as good as the near one.
  • Pinning an acquisition without checking coverage first. Names come from this endpoint. An acquisition that does not exist, or that exists but does not overlap your domain, is a 422 with two different messages.