Coverage
/coverage/export/coverage/geojsonPurpose
POST /coverage lays a grid over the Earth, propagates the constellation, and
reports per-point coverage together with the grid and configuration used.
POST /export/coverage/geojson returns the same analysis as GeoJSON, ready to
overlay in a mapping tool.
Coverage is geometry. Whether a usable signal arrives is
/link, and the two disagree routinely.
Request
| Parameter | Type | Unit | Default | Required | Description |
|---|---|---|---|---|---|
constellation_id | string | n/a | — | Yes | Identifier of an existing constellation. |
grid_deg | number | deg | — | Yes | Grid spacing. A hole smaller than this can fall between sample points. |
start | string | RFC 3339 UTC | 2026-01-01T00:00:00Z | No | Analysis start epoch. |
duration_hours | number | h | 6 | No | Analysis window length. |
step_seconds | number | s | 60 | No | Time step. A gap shorter than this is invisible. |
propagation_model | string | n/a | two_body | No | Propagation model. |
min_elevation_deg | number | deg | 10 | No | Elevation mask. A point counts as covered only above this angle. |
sensor_half_angle_deg | number | deg | — | No | Conical sensor half-angle. Null means line of sight subject to the mask. |
Example
curl -s -X POST http://127.0.0.1:8080/coverage \
-H 'content-type: application/json' \
-d '{
"constellation_id": "demo",
"duration_hours": 6.0,
"step_seconds": 120.0,
"grid_deg": 10.0
}'{
"status": "completed",
"satellite_count": 60,
"sample_count": 181,
"analysis": {
"start": "2026-01-01T00:00:00Z",
"step_seconds": 120.0,
"duration_seconds": 21600.0,
"grid": {
"min_lat_deg": -90.0,
"max_lat_deg": 90.0,
"min_lon_deg": -180.0,
"max_lon_deg": 180.0,
"step_deg": 10.0
},
"config": { "min_elevation_deg": 10.0, "sensor_half_angle_deg": null },
"points": [
{ "latitude_deg": -90.0, "longitude_deg": -180.0, "coverage_percent": 0.0 }
]
}
}Response elided; points holds one entry per grid point.
The response echoes its own configuration
analysis.grid and analysis.config repeat the settings the analysis actually
used. That is not redundancy, it is the defense against the ignored-field
behavior described in the API overview: if you misspell
min_elevation_deg, the request succeeds using the default 10 and config is
the only place that discrepancy is visible.
Check config against what you intended to send.
The first grid point is the whole story
The example response begins with the point at latitude -90, coverage 0.0 percent. That is the South Pole, and a 53-degree constellation never reaches it.
Inclination sets a hard latitude ceiling. Polar points are not poorly covered by this design, they are never covered at all, and no number of satellites fixes it.
Aggregate coverage percentages hide this completely. Always look at the minimum, and at the points that produce it.
Sample count and step
sample_count of 181 for a 6-hour window at 120 seconds is 180 steps plus the
closing endpoint. Halving the step doubles the samples and the run time, and it
is the only way to detect gaps shorter than the current step.
GeoJSON export
POST /export/coverage/geojson does not take a constellation_id. It
takes the analysis object that POST /coverage returns:
Failed to deserialize the JSON body into the target type: missing field `analysis`So it is a second step, not an alternative first step. Run the coverage
analysis, then hand its analysis object to the exporter.
# 1. Run the analysis.
curl -s -X POST http://127.0.0.1:8080/coverage \
-H 'content-type: application/json' \
-d '{"constellation_id":"gj","duration_hours":1.0,
"step_seconds":600.0,"grid_deg":45.0}' > cov.json
# 2. Wrap its `analysis` object and export.
python3 -c "import json;print(json.dumps({'analysis':json.load(open('cov.json'))['analysis']}))" \
| curl -s -X POST http://127.0.0.1:8080/export/coverage/geojson \
-H 'content-type: application/json' --data-binary @- > coverage.geojsonThe result is a FeatureCollection with one Point feature per grid point:
{
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [-180.0, -90.0] },
"properties": {
"coverage_percent": 0.0,
"max_fold": 0,
"max_gap_seconds": 0.0,
"mean_fold": 0.0,
"mean_gap_seconds": 0.0,
"outage_count": 0
}
}The export carries more per point than the coverage response prints:
max_fold, mean_fold, mean_gap_seconds, and outage_count are all
present. If you want per-point fold or outage counts, this is where they are.
GeoJSON coordinates are [longitude, latitude], in that order, which is the
reverse of how the coverage response lists them. That ordering is required by
the GeoJSON specification and is a routine source of transposed maps.
See also
orbitforge coveragefor the command-line equivalent, which reports summary statistics rather than per-point data.- Coverage and revisit.
main (pre-release)