{
  "openapi": "3.1.1",
  "info": {
    "title": "Satellite Change Explorer API",
    "version": "1.0.0",
    "summary": "Compare NASA satellite images of any place on two dates: true colour, NDVI, night lights.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://satellitechangeexplorer.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Compare NASA satellite images of any place on two dates: true colour, NDVI, night lights.",
        "description": "Pick a place (latitude/longitude + radius, or a bounding box) and two dates. The tool builds side-by-side NASA GIBS images for each chosen layer — MODIS/VIIRS true colour, 7-2-1 false colour, 30 m Harmonized Landsat Sentinel-2, NDVI composites and VIIRS night lights — with the resolution, revisit and cloud caveats you need to read them correctly.\n\nMethodology:\n- The area is a lat/lon box: from a centre, half-width r km gives ±r/111.32° latitude and ±r/(111.32·cos φ)° longitude. Image height follows the box aspect in degrees (plate carrée, EPSG:4326).\n- Images come from NASA GIBS via the Worldview Snapshot API (https://wvs.earthdata.nasa.gov/api/v1/snapshot, REQUEST=GetSnapshot, CRS=EPSG:4326, BBOX=south,west,north,east, TIME=YYYY-MM-DD); an equivalent GIBS WMS 1.3.0 GetMap URL is returned too.\n- Layer identifiers, maximum resolutions (tile-matrix sets), formats and first available dates were taken from the GIBS EPSG:4326 \"best\" WMTS capabilities. Composite layers are requested at the start of their period (16-day periods begin on day-of-year 1, 17, 33, …; monthly on day 1).\n- If one image pixel is smaller than half the layer resolution the result flags \"upsampled\": detail finer than the native resolution is interpolation, not information.\n- No automated change detection: the tool cannot download image pixels, so it does not compute change statistics. Compare visually and mind clouds, season, sun angle and sensor differences.\n\nImagery courtesy of NASA EOSDIS GIBS. Visual comparison only; not suitable for legal or insurance evidence without the source data.",
        "tags": [
          "public-data"
        ],
        "x-mcp-tool": "satellite_change_explorer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SatelliteChangeExplorerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Nile Delta, summer 2025 vs summer 2026: true colour + NDVI",
                  "value": {
                    "lat": 30.6,
                    "lon": 31.2,
                    "radiusKm": 80,
                    "dateBefore": "2025-07-20",
                    "dateAfter": "2026-07-20",
                    "layers": [
                      "modis-terra-truecolor",
                      "ndvi-16day"
                    ],
                    "width": 512
                  }
                },
                "example2": {
                  "summary": "Berlin at 30 m (HLS Sentinel-2), August 2025 vs August 2026",
                  "value": {
                    "bbox": "13.2,52.4,13.6,52.6",
                    "dateBefore": "2025-08-13",
                    "dateAfter": "2026-08-05",
                    "layers": [
                      "hls-sentinel2"
                    ],
                    "width": 640
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SatelliteChangeExplorerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "SatelliteChangeExplorerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "lat": {
            "title": "Latitude",
            "type": "number",
            "minimum": -85,
            "maximum": 85
          },
          "lon": {
            "title": "Longitude",
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "radiusKm": {
            "title": "Half-width of the area",
            "type": "number",
            "minimum": 1,
            "maximum": 1000,
            "default": 30,
            "x-unit": "km"
          },
          "bbox": {
            "title": "Or bounding box (west,south,east,north)",
            "description": "Overrides latitude/longitude when set.",
            "type": "string",
            "maxLength": 120
          },
          "dateBefore": {
            "title": "Before date",
            "description": "Default: one year before the \"after\" date.",
            "type": "string",
            "format": "date"
          },
          "dateAfter": {
            "title": "After date",
            "description": "Default: yesterday (UTC).",
            "type": "string",
            "format": "date"
          },
          "layers": {
            "title": "Layers",
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "modis-terra-truecolor",
                "modis-aqua-truecolor",
                "viirs-snpp-truecolor",
                "viirs-noaa20-truecolor",
                "modis-terra-721",
                "hls-sentinel2",
                "hls-landsat",
                "ndvi-16day",
                "ndvi-monthly",
                "night-lights"
              ]
            },
            "default": [
              "modis-terra-truecolor"
            ]
          },
          "width": {
            "title": "Image width",
            "type": "integer",
            "minimum": 128,
            "maximum": 1024,
            "default": 512,
            "x-unit": "px"
          }
        },
        "required": []
      },
      "SatelliteChangeExplorerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "bbox",
              "center",
              "areaKm",
              "image",
              "dates",
              "layers",
              "changeDetection"
            ],
            "properties": {
              "bbox": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "west",
                  "south",
                  "east",
                  "north"
                ],
                "properties": {
                  "west": {
                    "type": "number"
                  },
                  "south": {
                    "type": "number"
                  },
                  "east": {
                    "type": "number"
                  },
                  "north": {
                    "type": "number"
                  }
                }
              },
              "center": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "lat",
                  "lon"
                ],
                "properties": {
                  "lat": {
                    "type": "number"
                  },
                  "lon": {
                    "type": "number"
                  }
                }
              },
              "areaKm": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "width",
                  "height"
                ],
                "properties": {
                  "width": {
                    "type": "number"
                  },
                  "height": {
                    "type": "number"
                  }
                }
              },
              "image": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "width",
                  "height",
                  "kmPerPixel"
                ],
                "properties": {
                  "width": {
                    "type": "integer"
                  },
                  "height": {
                    "type": "integer"
                  },
                  "kmPerPixel": {
                    "type": "number"
                  }
                }
              },
              "dates": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "before",
                  "after",
                  "daysApart"
                ],
                "properties": {
                  "before": {
                    "type": "string"
                  },
                  "after": {
                    "type": "string"
                  },
                  "daysApart": {
                    "type": "integer"
                  }
                }
              },
              "layers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "key",
                    "gibsLayer",
                    "title",
                    "instrument",
                    "resolution",
                    "temporal",
                    "availableFrom",
                    "format",
                    "upsampled",
                    "before",
                    "after",
                    "notes"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "gibsLayer": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "instrument": {
                      "type": "string"
                    },
                    "resolution": {
                      "type": "string"
                    },
                    "temporal": {
                      "type": "string",
                      "enum": [
                        "daily",
                        "16-day",
                        "monthly"
                      ]
                    },
                    "availableFrom": {
                      "type": "string"
                    },
                    "format": {
                      "type": "string"
                    },
                    "upsampled": {
                      "type": "boolean"
                    },
                    "before": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "requestedDate",
                        "imageDate",
                        "available",
                        "snapshotUrl",
                        "wmsUrl"
                      ],
                      "properties": {
                        "requestedDate": {
                          "type": "string"
                        },
                        "imageDate": {
                          "type": "string"
                        },
                        "available": {
                          "type": "boolean"
                        },
                        "snapshotUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "wmsUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "after": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "requestedDate",
                        "imageDate",
                        "available",
                        "snapshotUrl",
                        "wmsUrl"
                      ],
                      "properties": {
                        "requestedDate": {
                          "type": "string"
                        },
                        "imageDate": {
                          "type": "string"
                        },
                        "available": {
                          "type": "boolean"
                        },
                        "snapshotUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "wmsUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    },
                    "notes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "changeDetection": {
                "type": "string",
                "description": "Always \"visual-only\": no pixel comparison is performed."
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}