Skip to content

STAC extension

Every Item we create declares the OAM extension:

https://docs.imagery.hotosm.org/oam/v0.2.0/schema.json

That URL is this site. docs/oam/v0.2.0/schema.json is a symlink to the source of truth in stac-extension/json-schema/, so publishing a schema change is a push to main.

Validation does not fetch it. The same schema ships inside the package and is registered with pystac before every Item.validate(), so ingestion does not depend on this site being up.

The full field definitions live in the extension README. What follows is what an ingestor has to get right.

What the schema enforces

Only three fields. An Item missing any of them fails validation and never reaches the catalogue:

  • gsd
  • oam:platform_type
  • oam:producer_name

What the app needs

The schema does not require these, but leave one out and the Item is invisible on the map, unfilterable, or undisplayable.

Field What to put in it What needs it
id A unique name. Don't use / in it Item lookups in the API break on slashes - swap them for -
geometry The image outline as GeoJSON, in lat/lon (EPSG:4326) The shape drawn on the browse map
bbox [west, south, east, north] of that outline "What imagery is in this area?" search
stac_extensions Must include https://docs.imagery.hotosm.org/oam/v0.2.0/schema.json Marks the item as OAM imagery, and turns on validation of the oam: fields below
properties.datetime When the image was taken The card, and the date filter. For a capture period, set it to null and give start_datetime / end_datetime - but the key must still be present
properties.title A human-readable name Card and sidebar heading
properties.gsd Pixel size on the ground, in metres The resolution filter. Imagery without it is hidden whenever that filter is used
properties.oam:platform_type One of kite, balloon, uav, aircraft, satellite The platform filter (drone / aircraft / satellite)
properties.oam:producer_name Name of the organisation or person who made the imagery, e.g. Maxar. Not an email address Attribution. Must match the first providers entry
properties.license One of CC-BY-4.0, CC-BY-SA-4.0, CC-BY-NC-4.0 The license filter. OAM only hosts open imagery, so anything else is rejected
providers Producer first, with name (same as oam:producer_name), roles: ["producer", "licensor"], and the contact in description - an email, or a team name if none can be published Cards show providers[0].name; description is how people get in touch
assets.visual Link to the imagery as a Cloud Optimized GeoTIFF (COG). Must be named visual The tile server draws from it, and it's the card's download link
assets.thumbnail Link to a small PNG preview The browse card picture. Items still work without one, but the card is blank

Imagery that crosses the date line

Split the geometry into two polygons either side of the 180° meridian, and write the bbox west edge first even though it's the bigger number (e.g. [179.5, -16, -179.5, -15]) - that's how a reader knows it wraps. Otherwise the item draws as a stripe across the whole map.

Optional fields

The uploader works these out from the image file. An ingested catalogue usually won't have them and OAM copes without, so fill in what your source provides and skip the rest.

Field What it is What you get for it
properties.start_datetime / end_datetime Start and end of capture Shows a date range instead of a single moment
properties.created When the item was added to OAM Tells "added recently" apart from "photographed recently"
properties.instruments Camera or sensor name, as a list Sensor shown on the card
properties.renders Display hints: which bands, how to stretch them, which colour ramp, what counts as empty Makes non-photo imagery (elevation, radar, multispectral) viewable. Without it the map shows raw bands
properties.oam:product_type visual, multispectral, sar, elevation or pseudocolor Picks the display hints above. Guessed from the file when not given
properties.oam:product_type_source declared if a person set the type, detected if it was guessed Says how much to trust the type
properties.oam:footprint_source mask if the outline follows the real image edge, bbox if it's just the rectangle Says how tight the outline on the map is
properties.oam:footprint_area Covered area in square metres Coverage stats
properties.oam:acquisition_time_estimated true when nobody supplied a capture date Warns that the date is a best guess
properties.oam:acquisition_source Where the date came from when the provider gave none: user, file-tags or ingest Says how good that guess is
properties.oam:external_id An ID from the system that sent the imagery, e.g. an ODM task Links the item back to that system
properties.processing:* software, version, lineage, datetime - what produced the file and how Provenance
assets.visual.file:size File size in bytes Download size on the card
assets.visual.file:checksum Checksum of the file Lets anyone confirm the download wasn't corrupted
assets.visual.bands Band names, with eo:common_name where known (red, nir, ...) Lets OAM pick sensible red/green/blue bands for display
assets.visual.proj:* Native projection, image size, transform Saves tools from opening the file to find out
assets.original Link to the untouched original file Archival, in case the converted copy is ever wrong
assets.metadata Link to the item's own JSON A stable copy of the record
assets.tms / assets.wmts Link to an existing tile service Used instead of OAM's tile server (older OAM items)
assets.*.alternate A second link to the same file, usually s3:// Direct bucket access for people who prefer it
links[rel=derived_from] Link to the original item in your catalogue Provenance for ingested imagery - worth adding for any third-party source
links[rel=via] Link to a public page about the imagery A "more info" backlink

Versions

Version Status
v0.2.0 current. Knows every oam: field above
v0.1.0 knows only oam:platform_type and oam:producer_name, and rejects any other oam: field

Both stay published at their own URL with their original definition, so older Items keep validating. Point new Items at v0.2.0, and add any oam: field of your own to the schema before using it.

Some Items still list a third URL, https://hotosm.github.io/stactools-hotosm/oam/v0.1.0/schema.json, served by GitHub Pages from the archived standalone repo. Nothing here resolves it any more, but external clients validating those Items do.

Upgrading Items to v0.2.0

Rebuilding an Item stamps it with the current version, so an upgrade is a re-ingest of the whole source.

A sync will not do it - it skips Items already in PgSTAC, so widening the window finds them and passes straight over. Dump and upsert instead:

hotosm dump-oam   --uploaded-after 2016-01-01 --handle-exceptions IGNORE --file oam.ndjson
hotosm dump-maxar --uploaded-after 2023-01-01 --handle-exceptions IGNORE --file maxar.ndjson

pypgstac load items --method upsert oam.ndjson
pypgstac load items --method upsert maxar.ndjson

Check what is left:

curl -s "https://api.imagery.hotosm.org/stac/search?limit=1" \
  | jq '.features[0].stac_extensions'

Adding a required field is a new version

Making an existing field required invalidates every Item in production at once. Publish the new version first, re-ingest onto it, and only then tighten the schema.

Creating a new version

See the package README.