{
  "openapi": "3.0.3",
  "info": {
    "title": "UK Postcode Intelligence API",
    "version": "0.1.0",
    "description": "One endpoint enrichment for any UK postcode. Combines crime, flood, EPC,\nschools, deprivation, and property prices into one normalised response.\n",
    "contact": {
      "name": "Stratum APIs",
      "url": "https://stratumapis.com",
      "email": "support@stratumapis.com"
    },
    "termsOfService": "https://stratumapis.com/legal/terms",
    "x-logo": {
      "url": "https://stratumapis.com/icon.svg",
      "altText": "Stratum APIs"
    }
  },
  "servers": [
    {
      "url": "https://api.stratumapis.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "StratumKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "StratumKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Stratum-Key"
      }
    },
    "schemas": {
      "Crime": {
        "type": "object",
        "properties": {
          "monthsObserved": {
            "type": "integer"
          },
          "totalCount": {
            "type": "integer"
          },
          "byCategory": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "nearbyCount": {
            "type": "integer",
            "description": "Count of crimes within ~1 mile of the postcode centroid in the most recent month available."
          }
        }
      },
      "FloodRisk": {
        "type": "object",
        "properties": {
          "riverAndSea": {
            "type": "string",
            "enum": [
              "very-low",
              "low",
              "medium",
              "high",
              "unknown"
            ]
          },
          "floodZone": {
            "type": "string",
            "nullable": true,
            "enum": [
              "1",
              "2",
              "3"
            ],
            "description": "Environment Agency Flood Map for Planning zone at the postcode centre. Null when never available."
          },
          "floodZoneSource": {
            "type": "string",
            "nullable": true,
            "description": "What the zone is from (river, sea, river and sea)."
          },
          "lastAvailable": {
            "type": "boolean",
            "description": "True when the Environment Agency did not answer and this is the last available result for the postcode (see asOf)."
          },
          "asOf": {
            "type": "string",
            "format": "date-time"
          },
          "nearestStation": {
            "type": "string",
            "nullable": true
          },
          "currentWarning": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Deprivation": {
        "type": "object",
        "properties": {
          "decile": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "description": "1 is most deprived, 10 is least deprived."
          },
          "rank": {
            "type": "integer",
            "description": "Out of approximately 32,844 LSOAs."
          },
          "lsoaCode": {
            "type": "string"
          }
        }
      },
      "PostcodeIntelligence": {
        "type": "object",
        "properties": {
          "postcode": {
            "type": "string"
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          },
          "localAuthority": {
            "type": "string"
          },
          "constituency": {
            "type": "string"
          },
          "crime": {
            "$ref": "#/components/schemas/Crime"
          },
          "flood": {
            "$ref": "#/components/schemas/FloodRisk"
          },
          "deprivation": {
            "$ref": "#/components/schemas/Deprivation"
          },
          "country": {
            "type": "string",
            "description": "England, Wales, Scotland or Northern Ireland. Landfill covers England; radon covers Great Britain."
          },
          "coalMining": {
            "$ref": "#/components/schemas/CoalMining"
          },
          "radon": {
            "$ref": "#/components/schemas/Radon"
          },
          "contaminatedLand": {
            "$ref": "#/components/schemas/ContaminatedLand"
          },
          "knotweed": {
            "$ref": "#/components/schemas/Knotweed"
          },
          "retrievedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CoalMining": {
        "type": "object",
        "description": "Mining Remediation Authority layers at the postcode centre (live point query).",
        "properties": {
          "band": {
            "type": "string",
            "enum": [
              "high",
              "low",
              "none"
            ]
          },
          "screened": {
            "type": "boolean",
            "description": "false: not checked; `band` is then not a finding. Read it first."
          },
          "recommendation": {
            "type": "string"
          },
          "asOf": {
            "type": "string",
            "description": "Set when the live source failed and this is the last answer for the postcode."
          }
        }
      },
      "Radon": {
        "type": "object",
        "description": "The BGS / UKHSA Indicative Atlas of Radon (1 km grid, Great Britain) at the postcode centre: the square's class is the highest radon potential anywhere in it, so it is indicative. Contains British Geological Survey materials © UKRI (Open Government Licence).",
        "properties": {
          "band": {
            "type": "string",
            "enum": [
              "very-low",
              "low",
              "medium",
              "medium-high",
              "high",
              "unknown"
            ]
          },
          "radonClass": {
            "type": "integer",
            "minimum": 1,
            "maximum": 6
          },
          "maxPotential": {
            "type": "string",
            "example": "5-10%",
            "description": "Highest share of homes above the Action Level in the square."
          },
          "gridSquare": {
            "type": "string",
            "example": "SK3587"
          },
          "testRecommended": {
            "type": "boolean",
            "nullable": true
          },
          "screened": {
            "type": "boolean",
            "description": "false: not checked (the atlas did not answer, or Northern Ireland). Read it first."
          },
          "recommendation": {
            "type": "string"
          },
          "attribution": {
            "type": "string"
          },
          "asOf": {
            "type": "string"
          }
        }
      },
      "Landfill": {
        "type": "object",
        "description": "The Environment Agency's historic and permitted landfill registers (England), within 500 m of the postcode centre: `high` = a site within 250 m, `medium` = within 500 m, `low` = none within 500 m.",
        "properties": {
          "band": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "unknown"
            ]
          },
          "approxNearbyCount": {
            "type": "integer",
            "nullable": true
          },
          "sites": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "closed",
                    "historic"
                  ]
                },
                "permitReference": {
                  "type": "string"
                },
                "withinMetres": {
                  "type": "integer",
                  "enum": [
                    250,
                    500
                  ]
                },
                "lastInput": {
                  "type": "string",
                  "format": "date"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "screened": {
            "type": "boolean",
            "description": "false: not checked (a register did not answer, or outside England). Read it first."
          },
          "recommendation": {
            "type": "string"
          },
          "attribution": {
            "type": "string"
          },
          "asOf": {
            "type": "string"
          }
        }
      },
      "ContaminatedLand": {
        "type": "object",
        "description": "The council's contaminated land register where we can read it (few councils publish it in a usable form, so `screened` is usually false), with the landfill answer alongside.",
        "properties": {
          "band": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low",
              "none",
              "unknown"
            ]
          },
          "screened": {
            "type": "boolean",
            "description": "True only when the council register was checked."
          },
          "laAdapterAvailable": {
            "type": "boolean"
          },
          "landfill": {
            "$ref": "#/components/schemas/Landfill"
          },
          "recommendation": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          }
        }
      },
      "Knotweed": {
        "type": "object",
        "description": "Recorded sightings of Japanese and giant knotweed within 500 m in the NBN Atlas (records licensed for commercial use only). Not a survey: most knotweed is never recorded.",
        "properties": {
          "band": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "unknown"
            ],
            "description": "low: none recorded; medium: 1-4; high: 5 or more."
          },
          "recordsWithin500m": {
            "type": "integer"
          },
          "latestRecordYear": {
            "type": "integer"
          },
          "recordsUrl": {
            "type": "string",
            "format": "uri"
          },
          "screened": {
            "type": "boolean",
            "description": "false: not checked (the atlas did not answer). Read it first."
          },
          "recommendation": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "attribution": {
            "type": "string"
          },
          "asOf": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/postcode/{postcode}": {
      "get": {
        "summary": "Get enriched intelligence for a UK postcode",
        "operationId": "getPostcode",
        "parameters": [
          {
            "name": "postcode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "SW1A1AA"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Enriched postcode record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostcodeIntelligence"
                }
              }
            }
          },
          "400": {
            "description": "Invalid postcode format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "404": {
            "description": "Postcode not found in our reference data"
          },
          "500": {
            "description": "Internal error"
          }
        }
      }
    },
    "/v1/postcode/bulk": {
      "post": {
        "summary": "Bulk lookup up to 100 postcodes in one request (Growth+)",
        "operationId": "getPostcodesBulk",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "postcodes"
                ],
                "properties": {
                  "postcodes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 100
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Array of postcode records (with `found: false` for misses)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "postcode": {
                            "type": "string"
                          },
                          "found": {
                            "type": "boolean"
                          },
                          "data": {
                            "description": "Postcode intelligence record. Null when `found` is false.",
                            "nullable": true,
                            "allOf": [
                              {
                                "$ref": "#/components/schemas/PostcodeIntelligence"
                              }
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body"
          },
          "401": {
            "description": "Missing or invalid API key"
          }
        }
      }
    },
    "/v1/postcode/{postcode}/neighbourhood-index": {
      "get": {
        "summary": "Composite neighbourhood index, A-F band per LSOA",
        "operationId": "getNeighbourhoodIndex",
        "description": "W30 iter 8. Returns the iter-5-design composite score from 12\nweighted inputs (crime rate / trend / forecast / IMD income /\nIMD employment / population density / tenure PRS / price-paid\ntrend / flood / MEES / radon / coal). Score 0-1 (0=best),\nbucketed into 6 equal-width bands. Missing inputs degrade\ngracefully and surface in the `missing` array. Radon comes from the\nBGS / UKHSA radon atlas since 2026-10-10 and coal from the Mining\nRemediation Authority since 2026-10-04.\n",
        "parameters": [
          {
            "name": "postcode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Neighbourhood-index card with score + band + sub-scores",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "postcode": {
                      "type": "string"
                    },
                    "score": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "band": {
                      "type": "string",
                      "enum": [
                        "A",
                        "B",
                        "C",
                        "D",
                        "E",
                        "F"
                      ]
                    },
                    "subScores": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "number"
                      }
                    },
                    "sources": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "missing": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "generatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Postcode not recognised"
          }
        }
      }
    },
    "/v1/postcode/{postcode}/crime-forecast": {
      "get": {
        "summary": "3-month direction-band crime forecast per category",
        "operationId": "getCrimeForecast",
        "description": "W30 iter 7 + iter 9 standalone exposure. Reads the per-(outcode,\ncategory) Holt-Winters direction-band rows the weekly forecast\ncron writes. Returns one row per display category. Surfaces\n`rising` / `stable` / `declining` per W30 iter-7 honest-\npresentation decision (we don't claim exact-count accuracy).\n",
        "parameters": [
          {
            "name": "postcode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-category direction-band forecast for the postcode's outcode",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "postcode": {
                      "type": "string"
                    },
                    "outcode": {
                      "type": "string"
                    },
                    "forecast": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "category": {
                            "type": "string"
                          },
                          "direction": {
                            "type": "string",
                            "enum": [
                              "rising",
                              "stable",
                              "declining"
                            ]
                          },
                          "forecastMean": {
                            "type": "number"
                          },
                          "confidenceBand": {
                            "type": "object",
                            "properties": {
                              "low": {
                                "type": "number"
                              },
                              "high": {
                                "type": "number"
                              }
                            }
                          },
                          "generatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "monthsObservedMin": {
                      "type": "integer",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Postcode not recognised"
          }
        }
      }
    }
  }
}