Skip to content

Download an area as GeoTIFF

Two routes cut an area out of the archive as GeoTIFF:

  • POST /v1/process on api.satellitedata.net, the v1 contract’s request shape (modelled on the Sentinel Hub Process API). Use it for new code.
  • POST /downloads on tiles.satellitedata.net, the download API the web map uses. It has more output options today: per-band files, previews and explicit mosaics.

Both run on the same renderer and write files that stay available for one day behind links that work for one hour. Their option names differ: process uses processing.clipNegative where the download API uses clamp.

Available now

Terminal window
curl -s -L -X POST https://api.satellitedata.net/v1/process \
-H "X-API-Key: $SDN_API_KEY" \
-H "Content-Type: application/json" \
-o area.tif \
-d '{
"input": {
"bounds": {"bbox": [-93.3, 44.9, -93.2, 45.0]},
"data": [{
"type": "landsat-ot-l2",
"dataFilter": {
"timeRange": {"from": "2026-07-01T00:00:00Z", "to": "2026-07-31T23:59:59Z"},
"maxCloudCoverage": 30,
"mosaickingOrder": "leastCC"
}
}]
},
"bands": ["blue", "green", "red", "nir08", "swir16", "swir22"],
"output": {"width": 1000, "height": 1100, "crs": "EPSG:4326"}
}'
  • input.bounds: a bbox (west, south, east, north), or a GeoJSON geometry, which lean v1 reads as its bounding box.
  • input.data: one source. dataFilter.timeRange searches the window in mosaickingOrder (mostRecent by default, leastCC for least cloudy first) and keeps the first scenes whose footprints together cover the box, at most 6. Or name the scenes with dataFilter.ids, a lean extension.
  • processing: units REFLECTANCE (the default, float32) or DN; harmonize offset_removed (the default) or none; clipNegative.
  • bands: common or native names; see Bands. The default is every spectral band.
  • output: width and height (at most 2,500 a side) or resx and resy, and crs (default EPSG:3857). The format is GeoTIFF.

Outputs up to 4 MB come back in the body. Larger ones answer 303 See Other with a presigned link valid for one hour, which curl -L follows. The GeoTIFF’s band descriptions are Earth Search asset keys (blue, green, red, nir08, …). See Process for every member and error.

To cut an exact scene, give its id:

"dataFilter": {"ids": ["S2C_T15TVK_20260712T171233_L2A"]}

Available now (a lean v1 extension)

For outputs over the synchronous limit (2,500 pixels a side), send the same body to POST /v1/process/jobs. The answer is 202 with the job’s id and a Location header; poll GET /v1/process/jobs/{jobId} until the job is done or failed.

Terminal window
curl -s -X POST https://api.satellitedata.net/v1/process/jobs \
-H "X-API-Key: $SDN_API_KEY" \
-H "Content-Type: application/json" \
-d @request.json
curl -s https://api.satellitedata.net/v1/process/jobs/$JOB_ID \
-H "X-API-Key: $SDN_API_KEY"

A job moves through queued, running, then done (with rel: result links to the files) or failed (with the error as a problem object). Every poll of a finished job returns fresh links. Jobs take up to 20,000 pixels a side and 600 million values, and run for up to 5 minutes; job records are deleted with their files after a day. See Process jobs.

import os, time, requests
API = "https://api.satellitedata.net/v1"
headers = {"X-API-Key": os.environ["SDN_API_KEY"]}
job = requests.post(f"{API}/process/jobs", json=body, headers=headers).json()
while True:
state = requests.get(f"{API}/process/jobs/{job['id']}", headers=headers).json()
if state["status"] in ("done", "failed"):
break
time.sleep(5)
for link in state.get("links", []):
if link["rel"] == "result":
print(link["title"], link["href"])

The download API on tiles.satellitedata.net

Section titled “The download API on tiles.satellitedata.net”

Available now This is the API behind the web map’s Download this area button. Its collection ids are Earth Search’s: sentinel-2-c1-l2a and landsat-c2-l2. It sends the key as x-api-key (header names are case-insensitive).

Terminal window
curl -s -X POST https://tiles.satellitedata.net/downloads \
-H "x-api-key: $SDN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"collection": "sentinel-2-c1-l2a",
"item": "S2C_T15TVK_20260712T171233_L2A",
"bbox": [-93.3, 44.9, -93.2, 45.0]
}'

Without bands, you get every spectral band of the scene: 12 for Sentinel-2, 7 for Landsat. The file is a tiled, deflate-compressed GeoTIFF in the box’s UTM zone at the finest band’s resolution, with band names, scales and offsets stored in it. The answer is JSON with a url to the file; download it within the hour:

Terminal window
curl -s -o scene.tif "$URL"
Field Values Default
bands Asset names (red, nir08, scl, qa_pixel) or Sentinel Hub names (B04, B8A, SCL, CLD, QA_PIXEL, ST_CDIST) every spectral band
crs utm (the box’s UTM zone) or an EPSG code such as EPSG:4326 utm
resolution metres the finest band: 10 m or 30 m
resolution_deg [dx, dy] in degrees, EPSG:4326 only
size [width, height] in pixels, overrides any resolution
units DN or REFLECTANCE DN
harmonize none or offset_removed (DN only) none
clamp true sets converted values below 0 to 0 false
output multiband (one file) or per_band (one file per band) multiband
preview {"width": 1024} adds a true-colour PNG none

In the download API, asset nir is Sentinel-2 B08, the broad NIR band. For cross-sensor work ask for nir08 (B8A); see the B08 trap.

The meaning of units, harmonize and clamp is on Values, scale and offset. Class, probability and QA layers always come back as stored.

"output": "per_band" writes one GeoTIFF per band, each in its own type: for example SCL stays uint8 while harmonized reflectance is int16. The answer’s files list has one entry per band with its url, filename, dtype, scale, offset, nodata, valid_fraction and items_used.

"preview": {"width": 1024} adds a true-colour PNG of the box (64 to 2,500 pixels wide; height follows the box), transparent where no scene has data, with its valid_fraction. It is a quick way to check a download before opening the GeoTIFF.

A box that crosses the edge of a Sentinel-2 tile or Landsat path needs more than one scene. Give items or datetime instead of item:

  • items: 1 to 6 scenes of one pass, by id.
  • datetime: a start/end window. The server takes every scene over the box from the platform of the clearest scene, at most 6.

Each pixel comes from the first scene that has data there, least cloudy first, or in your order with "order": "as_given". The answer lists items_used.

Terminal window
curl -s -X POST https://tiles.satellitedata.net/downloads \
-H "x-api-key: $SDN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"collection": "sentinel-2-c1-l2a",
"datetime": "2026-07-10T00:00:00Z/2026-07-14T23:59:59Z",
"bbox": [-93.4, 44.85, -93.1, 45.05],
"bands": ["B04", "B8A", "SCL"],
"harmonize": "offset_removed",
"clamp": true,
"output": "per_band",
"preview": {"width": 1024}
}'

A mosaic may read at most 200 million values × scenes in one request.

POST https://tiles.satellitedata.net/downloads/jobs takes the same body and returns 202 with an id and a poll path; GET /downloads/jobs/{id} returns queued, running, done (with the same fields as a direct download) or failed (with the error). Jobs allow 600 million values and 2.4 billion values × scenes.

Measured on 15 October 2026: a 35 × 23 km box with all 17 Sentinel-2 bands at 10 m in EPSG:4326, harmonized and mosaicked from 6 scenes across three UTM zones, finished in 53 seconds and produced 53 MB of files.

Request (measured 15 October 2026) Size Time
10 km square of Sentinel-2, default bands 12 MB 2.2 s
30 km square of Sentinel-2, default bands 77 MB 12 s
Largest synchronous request, 150 million values about 34 km square of Sentinel-2 or 134 km of Landsat about 16 s

Every request counts as one against the key’s monthly quota, whatever its size.

On POST /v1/process, the full contract adds expression (band math or an index id such as ndvi), preset, the unified cloudMask, exact geometry clipping, PNG, JPEG, WebP and JSON output, up to four data sources per request, and per-scene metadata in JSON output.