{
  "openapi": "3.1.0",
  "info": {
    "title": "Roof Pitch API",
    "version": "1.0.0",
    "summary": "Roof pitch, footprint and surface area for a New Zealand address.",
    "description": "Roof Pitch API is a REST API that turns a New Zealand street address into a measured roof pitch in degrees, the building footprint in square metres and the true roof surface area in square metres. It is built on Land Information New Zealand (LINZ) open data: the national address dataset, building outlines and 1 m LiDAR elevation. It covers Canterbury today, with the rest of New Zealand coming, and is sold by Product in Your Pocket in Christchurch.\n\nDocumentation: https://roofpitchapi.co.nz/docs/\n\nContains data sourced from Land Information New Zealand (LINZ), licensed CC BY 4.0.",
    "contact": {
      "name": "Anthony, Product in Your Pocket",
      "email": "anthony@productinyourpocket.com"
    },
    "license": {
      "name": "Data: CC BY 4.0 (LINZ)",
      "identifier": "CC-BY-4.0"
    }
  },
  "servers": [
    {
      "url": "https://api.roofpitchapi.co.nz/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/roofs": {
      "get": {
        "operationId": "getRoofByAddress",
        "summary": "Address in, measured roof out",
        "parameters": [
          {
            "name": "address",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The address as a person would type it."
          }
        ],
        "responses": {
          "200": {
            "description": "The matched address and its buildings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoofResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/addresses": {
      "get": {
        "operationId": "searchAddresses",
        "summary": "Address search and autocomplete",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "description": "Partial address, three or more characters."
          }
        ],
        "responses": {
          "200": {
            "description": "Up to ten candidates, best match first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressSearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/buildings/{id}": {
      "get": {
        "operationId": "getBuilding",
        "summary": "Measure one specific building",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "A building id from a /roofs response."
          }
        ],
        "responses": {
          "200": {
            "description": "The building's measurement.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Building"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/coverage": {
      "get": {
        "operationId": "getCoverage",
        "summary": "Where measured pitch is available",
        "security": [],
        "responses": {
          "200": {
            "description": "The covered territorial authorities.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoverageResponse"
                },
                "example": {
                  "territorialAuthorities": [
                    "Christchurch City",
                    "Selwyn District",
                    "Waimakariri District",
                    "Timaru District",
                    "Ashburton District",
                    "Hurunui District",
                    "Waimate District",
                    "Mackenzie District",
                    "Kaikoura District"
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued by email. rp_live_ keys count against quota; rp_test_ keys return the fixed sample."
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests allowed per sliding 60 seconds for this key."
      },
      "X-RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "schema": {
          "type": "integer"
        },
        "description": "Unix timestamp in seconds when the window resets."
      },
      "X-Quota-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Successful /roofs and /buildings lookups left this month."
      },
      "Retry-After": {
        "schema": {
          "type": "integer"
        },
        "description": "Seconds to wait, sent with 429 and 503."
      }
    },
    "responses": {
      "Error": {
        "description": "An error envelope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "Address": {
        "type": "object",
        "required": [
          "full",
          "territorialAuthority",
          "latitude",
          "longitude"
        ],
        "properties": {
          "full": {
            "type": "string"
          },
          "territorialAuthority": {
            "type": "string"
          },
          "latitude": {
            "type": "number"
          },
          "longitude": {
            "type": "number"
          }
        }
      },
      "Building": {
        "type": "object",
        "required": [
          "id",
          "footprintM2",
          "pitchDegrees",
          "pitchSource",
          "surfaceAreaM2"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "LINZ building outline id, stable across releases."
          },
          "footprintM2": {
            "type": "number",
            "description": "Plan area of the outline in square metres, one decimal place."
          },
          "pitchDegrees": {
            "type": "integer",
            "minimum": 0,
            "maximum": 59,
            "description": "Dominant roof slope from horizontal."
          },
          "pitchSource": {
            "type": "string",
            "enum": [
              "lidar",
              "default"
            ]
          },
          "pitchConfidence": {
            "type": "string",
            "enum": [
              "high",
              "medium",
              "low"
            ],
            "description": "Present only when pitchSource is lidar."
          },
          "surfaceAreaM2": {
            "type": "number",
            "description": "footprintM2 / cos(pitchDegrees), one decimal place."
          },
          "territorialAuthority": {
            "type": "string",
            "description": "Present on /buildings/{id} responses."
          }
        }
      },
      "RoofResponse": {
        "type": "object",
        "required": [
          "address",
          "building",
          "otherBuildings",
          "attribution"
        ],
        "properties": {
          "address": {
            "$ref": "#/components/schemas/Address"
          },
          "building": {
            "$ref": "#/components/schemas/Building"
          },
          "otherBuildings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Building"
            }
          },
          "attribution": {
            "type": "string"
          }
        }
      },
      "AddressCandidate": {
        "type": "object",
        "required": [
          "full",
          "territorialAuthority",
          "covered"
        ],
        "properties": {
          "full": {
            "type": "string"
          },
          "territorialAuthority": {
            "type": "string"
          },
          "covered": {
            "type": "boolean"
          }
        }
      },
      "AddressSearchResponse": {
        "type": "object",
        "required": [
          "candidates"
        ],
        "properties": {
          "candidates": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/AddressCandidate"
            }
          }
        }
      },
      "CoverageResponse": {
        "type": "object",
        "required": [
          "territorialAuthorities"
        ],
        "properties": {
          "territorialAuthorities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "requestId"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "ADDRESS_NOT_FOUND",
                  "OUT_OF_AREA",
                  "NO_BUILDING_FOUND",
                  "UNAUTHORIZED",
                  "INVALID_REQUEST",
                  "BUILDING_NOT_FOUND",
                  "RATE_LIMITED",
                  "MEASUREMENT_UNAVAILABLE",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string"
              },
              "issues": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              },
              "requestId": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}