{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/thinair-co/json-schema/thinair-co-explore-response-schema.json",
  "title": "ExploreResponse",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/geo-thinair-co-openapi.json#/components/schemas/ExploreResponse",
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ExploreItem"
      }
    },
    "meta": {
      "type": "object",
      "properties": {
        "upstream_ms": {
          "type": "number"
        },
        "feature_count": {
          "type": "number"
        },
        "cacheHit": {
          "type": "boolean"
        },
        "query": {
          "type": "string"
        },
        "center_lat": {
          "type": "number"
        },
        "center_lon": {
          "type": "number"
        },
        "center_label": {
          "type": "string"
        },
        "radius_km": {
          "type": "number",
          "description": "Search radius actually applied, in kilometers (the canonical unit) — 150 on the default path. Present on every response except the legacy unparseable-radius fall-through, where the engine decided."
        },
        "radius": {
          "type": "number",
          "description": "The applied radius expressed in `units`, rounded to 3 decimals — 93.206 (miles) on the default path, 150 with `units=kilometers`."
        },
        "units": {
          "type": "string",
          "enum": [
            "miles",
            "kilometers"
          ],
          "description": "Display unit of `radius`: the request's `units` if sent; else the unit of a suffixed `radius` string ('30mi' → miles, '30km' / '800m' → kilometers); else miles — the platform default, which also covers a bare numeric `radius` and the no-input path. `units` alone does not supply a radius; it only selects this."
        },
        "layers": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "locality",
              "neighbourhood",
              "borough",
              "county",
              "region"
            ]
          },
          "description": "The layers actually served, in the order requested. A layer that received no share of `size` is absent here and `truncated` is true."
        },
        "ranking": {
          "type": "string",
          "description": "Plain-language statement of the ranking basis actually applied."
        },
        "truncated": {
          "type": "boolean",
          "description": "True when a layer produced more candidates than its share of `size`. False means no truncation was observed — with no upstream total, it is not a claim that nothing more exists."
        },
        "total_candidates": {
          "type": "integer",
          "description": "Count of matching candidates upstream, before this API's `min_population` filter and duplicate-place removal are applied — NOT the number of items in this response's `items` array, and not how many more results you could page through. Present ONLY when the backend reports a true, exact total for every layer served; omitted when it cannot (including whenever `min_population` is greater than zero; an explicit `min_population: 0` means no filter and keeps the exact total), and never estimated."
        }
      },
      "required": [
        "upstream_ms",
        "feature_count",
        "query"
      ]
    },
    "upstream_error": {
      "type": [
        "string",
        "null"
      ]
    },
    "structured_error": {
      "$ref": "#/$defs/StructuredError"
    }
  },
  "required": [
    "items",
    "meta"
  ],
  "$defs": {
    "ExploreItem": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "layer": {
          "type": "string",
          "description": "The place's own layer — one of locality, neighbourhood, borough, county, region. This is the classification; there is no other tier field."
        },
        "population": {
          "type": "number",
          "description": "Population, present ONLY where the source carries one (coverage is partial and varies by layer). Absent means unknown — never zero-filled."
        },
        "distance_km": {
          "type": "number",
          "description": "Distance from the center point in kilometers (the canonical unit)."
        },
        "distance": {
          "type": "number",
          "description": "The same distance in the request's display unit (`meta.units`), 1 decimal."
        },
        "distance_unit": {
          "type": "string",
          "enum": [
            "miles",
            "kilometers"
          ],
          "description": "Display unit of `distance` — always equal to `meta.units`."
        },
        "bearing": {
          "type": "integer",
          "minimum": 0,
          "maximum": 359,
          "description": "Initial bearing from the center point to this place, integer degrees 0-359 clockwise from true north."
        },
        "coordinates": {
          "type": "object",
          "properties": {
            "lat": {
              "type": "number",
              "minimum": -90,
              "maximum": 90,
              "description": "Latitude in decimal degrees, WGS84."
            },
            "lon": {
              "type": "number",
              "minimum": -180,
              "maximum": 180,
              "description": "Longitude in decimal degrees, WGS84."
            }
          },
          "required": [
            "lat",
            "lon"
          ]
        },
        "region": {
          "type": "string"
        },
        "country": {
          "type": "string"
        }
      }
    },
    "StructuredError": {
      "type": "object",
      "properties": {
        "code": {
          "type": "string",
          "description": "Stable, snake_case identifier callers can switch on."
        },
        "message": {
          "type": "string"
        },
        "details": {
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "code",
        "message"
      ]
    }
  }
}