{
  "openapi": "3.0.3",
  "info": {
    "title": "getAddress() New Zealand API",
    "description": "Simple APIs for New Zealand addresses, built on LINZ\u0027s NZ Addresses. Autocomplete, Location, Typeahead and Distance are free and rate limited; resolving a suggestion with Get or Get Location, a Validate that finds its address, and a Nearest or Nearest Location that finds something each count as one look-up. Reporting a wrong postcode is free. Supply your API key as the \u0060api-key\u0060 query parameter \u2014 it is the only place the key is read from. Browser code should use a domain token in place of the API key. Usage takes the subscription\u0027s admin key. Address ids are LINZ \u0060address_id\u0060s. Coordinates are WGS84. Postcodes are unofficial: they come from the open_nz_postcodes project, not NZ Post, and are wrong for roughly 5 addresses in 100, so every address carries a \u0060postcode_source\u0060 saying how its postcode was assigned. Address data is NZ Addresses from Toit\u016B Te Whenua Land Information New Zealand, sourced from the LINZ Data Service (https://data.linz.govt.nz/) and licensed for reuse under the CC BY 4.0 licence (https://creativecommons.org/licenses/by/4.0/).",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.getaddress.nz"
    }
  ],
  "security": [
    {
      "ApiKeyQuery": []
    }
  ],
  "paths": {
    "/autocomplete/{term}": {
      "get": {
        "operationId": "autocomplete",
        "summary": "Suggest addresses for a term",
        "description": "Returns up to \u0060top\u0060 suggestions for the given term. Macrons are optional: \u0060otahuhu\u0060 finds \u014Ct\u0101huhu. Autocomplete queries are rate limited but do not increase your usage. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "The partial address to search for, e.g. \u0060169 lambton\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of suggestions to return (max 6).",
            "schema": {
              "type": "integer",
              "default": 6,
              "maximum": 6
            }
          },
          {
            "name": "template",
            "in": "query",
            "required": false,
            "description": "Suggestion text template, e.g. \u0060{formatted_address}\u0060. \u0060{name,prefix,suffix}\u0060 wraps a non-empty field with the given prefix/suffix. Available fields: formatted_address, locality (or suburb), suburb_locality, town_city, postcode, postcode_source.",
            "schema": {
              "type": "string",
              "default": "{formatted_address}"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suggestions for the term.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Suggestions"
                },
                "example": {
                  "suggestions": [
                    {
                      "address": "169 Lambton Quay, Wellington Central, Wellington 6011",
                      "url": "/get/363752",
                      "id": "363752"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "autocompletePost",
        "summary": "Suggest addresses for a term (options body)",
        "description": "Identical to the GET, with an optional JSON body carrying top, template, a filter (town_city, locality, postcode, radius), a location to prefer nearby suggestions, and your end user\u0027s ip_address. Accepts a domain token in place of an API key, in which case nearby suggestions are preferred automatically.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "The partial address to search for, e.g. \u006012 queen st\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AutocompleteOptions"
              },
              "example": {
                "top": 6,
                "filter": {
                  "town_city": "Auckland",
                  "postcode": "1010"
                },
                "location": {
                  "latitude": -36.8485,
                  "longitude": 174.7633
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Suggestions for the term.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Suggestions"
                },
                "example": {
                  "suggestions": [
                    {
                      "address": "12 Queen Street, Auckland Central, Auckland 1010",
                      "url": "/get/1131927",
                      "id": "1131927"
                    },
                    {
                      "address": "12A Queen Street, Auckland Central, Auckland 1010",
                      "url": "/get/1385704",
                      "id": "1385704"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/get/{id}": {
      "get": {
        "operationId": "get",
        "summary": "Resolve a suggestion id to the full address",
        "description": "Returns the full address for a suggestion id. Each successful request counts as one look-up against your plan\u0027s allowance. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The address\u0027s LINZ \u0060address_id\u0060, as returned in the \u0060id\u0060 of an \u0060/autocomplete/{term}\u0060 suggestion, e.g. \u0060363752\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The full address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                },
                "example": {
                  "id": "363752",
                  "address_id": "363752",
                  "address_label": "169 Lambton Quay, Wellington Central, Wellington 6011",
                  "address_status": "current",
                  "flat_number": "",
                  "number_first": "169",
                  "number_last": "",
                  "number_suffix": "",
                  "full_road_name": "Lambton Quay",
                  "locality_name": "Wellington Central",
                  "town_city": "Wellington",
                  "territorial_authority": "Wellington City",
                  "postcode": "6011",
                  "postcode_source": "road",
                  "coordinates": {
                    "latitude": -41.2828093667,
                    "longitude": 174.7759540167
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "No address exists for the given id."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable. Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/validate/{address}": {
      "get": {
        "operationId": "validate",
        "summary": "Confirm a one-line address",
        "description": "Returns the one address a line of text describes, exactly as /get/{id} returns it, and counts one look-up. When the line fits several addresses, or names no suburb or postcode, answers 300 with their ids and costs nothing; when it fits none, 404. A level (\u0022Level 5\u0022) or a rural delivery number (\u0022RD 2\u0022) in the line is read off and ignored, as LINZ holds neither. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "The address on one line, e.g. \u00602/12 East Street, Auckland Central, Auckland 1010\u0060. URL-encode it, but leave a flat\u0027s slash as it is: \u00602/12 East Street ...\u0060 reads as flat 2, number 12.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Exactly one address fits: it is returned exactly as /get/{id} returns it. Counts one look-up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              }
            }
          },
          "300": {
            "description": "Several addresses fit, the line names no suburb or postcode, or it names a building LINZ holds only as its units. Their ids, up to 10, with primary_secondary \u0022PRIMARY\u0022 when they are the units of the one building the line names (only the unit is missing). Costs nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateCandidates"
                },
                "example": {
                  "candidates": [
                    "1131927",
                    "1186326"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The line is longer than 200 characters."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "No address fits every word of the line. Costs nothing."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable. Retry shortly."
          }
        }
      },
      "post": {
        "operationId": "validatePost",
        "summary": "Confirm a one-line address (POST)",
        "description": "Identical to the GET. Returns the one address a line of text describes, exactly as /get/{id} returns it, and counts one look-up. When the line fits several addresses, or names no suburb or postcode, answers 300 with their ids and costs nothing; when it fits none, 404. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "address",
            "in": "path",
            "required": true,
            "description": "The address on one line, e.g. \u00602/12 East Street, Auckland Central, Auckland 1010\u0060. URL-encode it, but leave a flat\u0027s slash as it is: \u00602/12 East Street ...\u0060 reads as flat 2, number 12.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Exactly one address fits: it is returned exactly as /get/{id} returns it. Counts one look-up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Address"
                }
              }
            }
          },
          "300": {
            "description": "Several addresses fit, the line names no suburb or postcode, or it names a building LINZ holds only as its units. Their ids, up to 10, with primary_secondary \u0022PRIMARY\u0022 when they are the units of the one building the line names (only the unit is missing). Costs nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateCandidates"
                },
                "example": {
                  "candidates": [
                    "1131927",
                    "1186326"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The line is longer than 200 characters."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "No address fits every word of the line. Costs nothing."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable. Retry shortly."
          }
        }
      }
    },
    "/nearest/{latitude}/{longitude}": {
      "get": {
        "operationId": "nearest",
        "summary": "The addresses nearest a point (reverse geocoding)",
        "description": "Returns up to \u0060top\u0060 addresses within \u0060radius\u0060 km of the point, nearest first, each with its distance in metres and an \u0060id\u0060 for \u0060/get/{id}\u0060. Flats are left out: they share their building\u0027s position, so the building\u0027s own address stands for them. A request that finds an address counts as one look-up against your plan\u0027s allowance; nothing within the radius returns an empty list and costs nothing. \u0060POST\u0060 the same URL for the same answer. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "latitude",
            "in": "path",
            "required": true,
            "description": "Latitude in decimal degrees (WGS84), e.g. \u0060-41.2828\u0060.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "longitude",
            "in": "path",
            "required": true,
            "description": "Longitude in decimal degrees (WGS84), e.g. \u0060174.7760\u0060.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of addresses to return (max 20).",
            "schema": {
              "type": "integer",
              "default": 1,
              "maximum": 20
            }
          },
          {
            "name": "radius",
            "in": "query",
            "required": false,
            "description": "How far from the point to look, in km (more than 0, at most 1).",
            "schema": {
              "type": "number",
              "format": "double",
              "default": 0.2,
              "exclusiveMinimum": 0,
              "maximum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The nearest addresses, nearest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearestAddresses"
                },
                "example": {
                  "suggestions": [
                    {
                      "address": "169 Lambton Quay, Wellington Central, Wellington 6011",
                      "url": "/get/363752",
                      "id": "363752",
                      "distance": 4
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The latitude, longitude or radius is out of range."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/distance/{from}/{to}": {
      "get": {
        "operationId": "distance",
        "summary": "Distance between two addresses or locations",
        "description": "Returns the straight-line distance in metres between two addresses or places, given LINZ address_ids or location ids (a place is measured from its centre), in any mix. Metres only, never coordinates. Rate limited but does not increase your usage. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "from",
            "in": "path",
            "required": true,
            "description": "The first address\u0027s LINZ address_id, e.g. \u0060363752\u0060, or a location id, e.g. \u0060Wellington Central|Wellington|6011\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "path",
            "required": true,
            "description": "The second address\u0027s LINZ address_id or location id, e.g. \u00601131927\u0060 or \u0060Rolleston|Rolleston|7614\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The straight-line distance in whole metres.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Distance"
                },
                "example": {
                  "metres": 493565
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "An id is unknown, or its address has no coordinates. The problem names which, from or to."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable. Retry shortly."
          }
        }
      }
    },
    "/distance/{fromLatitude}/{fromLongitude}/to/{toLatitude}/{toLongitude}": {
      "get": {
        "operationId": "distanceBetweenPoints",
        "summary": "Distance between two points",
        "description": "Returns the straight-line distance in metres between two latitude/longitude points. Rate limited but does not increase your usage. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "fromLatitude",
            "in": "path",
            "required": true,
            "description": "Latitude of the first point, e.g. \u0060-41.2865\u0060.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "fromLongitude",
            "in": "path",
            "required": true,
            "description": "Longitude of the first point.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "toLatitude",
            "in": "path",
            "required": true,
            "description": "Latitude of the second point.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "toLongitude",
            "in": "path",
            "required": true,
            "description": "Longitude of the second point.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -180,
              "maximum": 180
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The straight-line distance in whole metres.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Distance"
                }
              }
            }
          },
          "400": {
            "description": "A latitude or longitude is out of range."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The address data is briefly unavailable. Retry shortly."
          }
        }
      }
    },
    "/location/{term}": {
      "get": {
        "operationId": "location",
        "summary": "Suggest places for a partly typed suburb, town or postcode",
        "description": "Returns up to \u0060top\u0060 places \u2014 one per suburb, town and postcode \u2014 for the given term. Location queries are rate limited but do not increase your usage. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "The partly typed place name, e.g. \u0060norman\u0060.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of suggestions to return (max 20).",
            "schema": {
              "type": "integer",
              "default": 6,
              "maximum": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Places matching the term.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationSuggestions"
                },
                "example": {
                  "suggestions": [
                    {
                      "location": "Normanby, H\u0101wera 4614",
                      "url": "/get-location/Normanby%7CH%C4%81wera%7C4614",
                      "id": "Normanby|H\u0101wera|4614"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "locationPost",
        "summary": "Suggest places for a partly typed suburb, town or postcode (options body)",
        "description": "Identical to the GET, with an optional JSON body carrying top, a filter (town_city, postcode, radius), a location to prefer nearby places, and your end user\u0027s ip_address. Accepts a domain token in place of an API key, in which case nearby places are preferred automatically.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "The partly typed place name, e.g. \u0060norman\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationOptions"
              },
              "example": {
                "top": 6,
                "filter": {
                  "town_city": "H\u0101wera"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Places matching the term.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationSuggestions"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/get-location/{id}": {
      "get": {
        "operationId": "getLocation",
        "summary": "Resolve a location id to the place and its centre",
        "description": "Returns the suburb, town, territorial authority, postcode and centre for a location suggestion id. Each successful request counts as one look-up against your plan\u0027s allowance. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The place\u0027s location id, as returned in the \u0060id\u0060 of a \u0060/location/{term}\u0060 suggestion: suburb, town and postcode joined by \u0060|\u0060, e.g. \u0060Normanby|H\u0101wera|4614\u0060. URL-encode it (\u0060|\u0060 is \u0060%7C\u0060). A place with no postcode ends in \u0060|\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The place and its centre.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Place"
                },
                "example": {
                  "id": "Wellington Central|Wellington|6011",
                  "location": "Wellington Central, Wellington 6011",
                  "locality_name": "Wellington Central",
                  "town_city": "Wellington",
                  "territorial_authority": "Wellington City",
                  "postcode": "6011",
                  "coordinates": {
                    "latitude": -41.284889,
                    "longitude": 174.774879
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "404": {
            "description": "No place exists for the given id."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/nearest-location/{latitude}/{longitude}": {
      "get": {
        "operationId": "nearestLocation",
        "summary": "The places nearest a point",
        "description": "Returns up to \u0060top\u0060 places whose centres are nearest the point, nearest first, each with its distance in metres. A request that finds a place counts as one look-up against your plan\u0027s allowance; a point outside New Zealand returns an empty list and costs nothing. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "latitude",
            "in": "path",
            "required": true,
            "description": "Latitude in decimal degrees (WGS84), e.g. \u0060-41.2828\u0060.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "longitude",
            "in": "path",
            "required": true,
            "description": "Longitude in decimal degrees (WGS84), e.g. \u0060174.7760\u0060.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of places to return (max 20).",
            "schema": {
              "type": "integer",
              "default": 6,
              "maximum": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The nearest places, nearest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearestLocations"
                },
                "example": {
                  "suggestions": [
                    {
                      "location": "Wellington Central, Wellington 6011",
                      "url": "/get-location/Wellington%20Central%7CWellington%7C6011",
                      "id": "Wellington Central|Wellington|6011",
                      "distance": 250
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The latitude or longitude is out of range."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded, or the plan\u0027s daily look-up limit reached.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/typeahead/{term}": {
      "get": {
        "operationId": "typeahead",
        "summary": "Complete a partly typed street, suburb, town or postcode",
        "description": "Returns up to \u0060top\u0060 values as a JSON array of strings, drawn from every field alike (street, suburb, town and postcode). Typeahead queries are rate limited but do not increase your usage. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "What has been typed so far, e.g. \u0060otah\u0060 or \u006060\u0060.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 50
            }
          },
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of values to return (max 20).",
            "schema": {
              "type": "integer",
              "default": 6,
              "maximum": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Completed values, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TypeaheadValues"
                }
              }
            }
          },
          "400": {
            "description": "A term over 50 characters."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "typeaheadPost",
        "summary": "Complete a partly typed suburb, town or postcode (options body)",
        "description": "Identical to the GET, with an optional JSON body carrying top, search (the fields to complete: street, locality, town_city, postcode), a filter (town_city, locality, postcode) and same \u2014 e.g. the suburbs of one town. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "term",
            "in": "path",
            "required": true,
            "description": "What has been typed so far, e.g. \u0060n\u0060.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 50
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TypeaheadOptions"
              },
              "example": {
                "search": [
                  "locality"
                ],
                "filter": {
                  "town_city": "H\u0101wera"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Completed values, best first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TypeaheadValues"
                },
                "example": [
                  "Normanby"
                ]
              }
            }
          },
          "400": {
            "description": "An unknown search field, or a term over 50 characters."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but cannot make this request: the subscription has expired, or the key is the admin key (which reads usage only) or is tied to no subscription."
          },
          "429": {
            "description": "Rate limit exceeded for your plan\u0027s 5-minute span.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until a successful retry can be made.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The data is briefly unavailable (never answered as an empty list). Retry shortly.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/postcode-correction/{id}": {
      "post": {
        "operationId": "postcodeCorrection",
        "summary": "Report a wrong postcode",
        "description": "Reports that an address has the wrong postcode. One address per request; a second report from your account on the same address replaces the first. Corrections are applied at the weekly rebuild, not straight away: one account\u0027s report applies to its address; when accounts disagree, two or more agreeing accounts win, otherwise it waits for review; when two or more accounts\u0027 corrections on one road agree, the postcode spreads to the road. Free, and limited to 100 a day per API key (20 a day per visitor with a domain token). Only report what you or your user know first-hand, never postcodes copied from NZ Post products or its finder. Accepts a domain token in place of an API key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The address\u0027s LINZ address_id, as returned in the id of an /autocomplete/{term} suggestion, e.g. \u0060363752\u0060.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostcodeCorrectionRequest"
              },
              "example": {
                "postcode": "6140",
                "source": "customer",
                "note": "returned mail"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted: the correction is pending until the weekly rebuild.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostcodeCorrectionResponse"
                },
                "example": {
                  "id": "8f2c1e0a7b9d4c3e8f2c1e0a7b9d4c3e",
                  "address_id": "363752",
                  "postcode": "6140",
                  "previous_postcode": "6011",
                  "source": "customer",
                  "status": "pending",
                  "created": "2026-10-07T09:00:00\u002B00:00"
                }
              }
            }
          },
          "400": {
            "description": "The postcode is not four digits or no New Zealand address has it, the source is not \u0060user\u0060 or \u0060customer\u0060, or the note is longer than 200 characters."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Your account\u0027s reports are paused after review."
          },
          "404": {
            "description": "No address has this id."
          },
          "409": {
            "description": "The address already has that postcode."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections": {
      "get": {
        "operationId": "postcodeCorrections",
        "summary": "List your postcode corrections",
        "description": "Returns your account\u0027s postcode corrections, newest first, with where each stands: pending, applied, superseded or rejected. Free. Takes an API key; domain tokens are refused.",
        "parameters": [
          {
            "name": "top",
            "in": "query",
            "required": false,
            "description": "Number of corrections to return (default 50, max 200).",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Your account\u0027s corrections, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostcodeCorrectionsResponse"
                },
                "example": {
                  "corrections": [
                    {
                      "id": "8f2c1e0a7b9d4c3e8f2c1e0a7b9d4c3e",
                      "address_id": "363752",
                      "postcode": "6140",
                      "previous_postcode": "6011",
                      "source": "customer",
                      "status": "pending",
                      "created": "2026-10-07T09:00:00\u002B00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "A domain token: the list takes an API key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review": {
      "get": {
        "operationId": "postcodeReviewQueue",
        "summary": "List postcode corrections waiting for review",
        "description": "Staff only. Lists addresses with corrections still pending, disputed ones first (at most 100): the address, its postcode now, and each reported postcode with the accounts behind it. Also lists the paused accounts. Requires the admin key of a reviewer\u0027s subscription.",
        "responses": {
          "200": {
            "description": "Addresses waiting for review.",
            "content": {
              "application/json": {
                "example": {
                  "addresses": [
                    {
                      "address_id": "363752",
                      "address": "12 Example Street, Te Aro, Wellington 6011",
                      "postcode": "6011",
                      "postcode_source": "road",
                      "disputed": true,
                      "reason": "Accounts disagree: 6140 (1), 6021 (1).",
                      "proposals": [
                        {
                          "postcode": "6140",
                          "accounts": 1,
                          "reports": [
                            {
                              "id": "8f2c1e0a7b9d4c3e8f2c1e0a7b9d4c3e",
                              "account": "acme",
                              "source": "customer",
                              "note": "returned mail",
                              "created": "2026-10-07T09:00:00\u002B00:00"
                            }
                          ]
                        }
                      ]
                    }
                  ],
                  "paused_accounts": [
                    {
                      "account": "copier",
                      "paused_by": "lee",
                      "paused": "2026-10-08T09:00:00\u002B00:00",
                      "reason": "high volume across many roads"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review/{addressId}": {
      "post": {
        "operationId": "postcodeReview",
        "summary": "Accept or reject an address\u0027s postcode corrections",
        "description": "Staff only. \u0060accept\u0060 one reported postcode: the address\u0027s other reports are rejected and it is applied at the next weekly run. \u0060reject\u0060 rejects every report so the address keeps its usual postcode (one already applied goes back at the next weekly run). Requires the admin key of a reviewer\u0027s subscription.",
        "parameters": [
          {
            "name": "addressId",
            "in": "path",
            "required": true,
            "description": "The address\u0027s LINZ address_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "accept",
                      "reject"
                    ]
                  },
                  "postcode": {
                    "type": "string",
                    "description": "For accept: the reported postcode that wins."
                  }
                },
                "required": [
                  "action"
                ]
              },
              "example": {
                "action": "accept",
                "postcode": "6140"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What changed.",
            "content": {
              "application/json": {
                "example": {
                  "address_id": "363752",
                  "postcode": "6140",
                  "accepted": 1,
                  "rejected": 1
                }
              }
            }
          },
          "400": {
            "description": "The action is not \u0060accept\u0060 or \u0060reject\u0060, or accept has no four-digit postcode."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "404": {
            "description": "No reports for this address, or none of the postcode to accept."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review/accounts/{account}/pause": {
      "post": {
        "operationId": "postcodeReviewPause",
        "summary": "Pause an account\u0027s postcode corrections",
        "description": "Staff only. Rejects every correction the account has made (postcodes already applied go back at the next weekly run), and its new ones are refused with 403. Requires the admin key of a reviewer\u0027s subscription.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The account name, as the review queue lists it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "reason": "high volume across many roads"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paused; \u0060rejected\u0060 is how many reports were rejected.",
            "content": {
              "application/json": {
                "example": {
                  "address_id": "",
                  "postcode": "",
                  "accepted": 0,
                  "rejected": 42
                }
              }
            }
          },
          "400": {
            "description": "No account named, or your own."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review/neighbours": {
      "get": {
        "operationId": "postcodeReviewNeighbours",
        "summary": "List addresses whose neighbours disagree",
        "description": "Staff only. Lists addresses whose postcode differs from most of their 10 nearest addresses\u0027 (the weekly neighbour check), clearest first (at most 100). Nothing is corrected automatically; each is lower confidence until reviewed. Requires the admin key of a reviewer\u0027s subscription.",
        "responses": {
          "200": {
            "description": "Open neighbour flags.",
            "content": {
              "application/json": {
                "example": {
                  "flags": [
                    {
                      "address_id": "363752",
                      "address": "12 Example Street, Te Aro, Wellington 6011",
                      "postcode": "6011",
                      "postcode_source": "suburb (majority)",
                      "confidence": "low",
                      "neighbour_postcode": "6021",
                      "agreeing": 9,
                      "neighbours": 10,
                      "flagged": "2026-10-19T15:04:00\u002B00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review/neighbours/{addressId}": {
      "post": {
        "operationId": "postcodeReviewNeighbour",
        "summary": "Accept a postcode for, or dismiss, a neighbour flag",
        "description": "Staff only. \u0060accept\u0060 a postcode: saved as a correction in your name and applied at the next weekly run; the address\u0027s other reports for another postcode are rejected. Accepting the postcode it has is a dismissal. \u0060dismiss\u0060: the address keeps its postcode and the same finding is not raised again. Requires the admin key of a reviewer\u0027s subscription.",
        "parameters": [
          {
            "name": "addressId",
            "in": "path",
            "required": true,
            "description": "The address\u0027s LINZ address_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "accept",
                      "dismiss"
                    ]
                  },
                  "postcode": {
                    "type": "string",
                    "description": "For accept: the postcode the address should have, usually neighbour_postcode."
                  }
                },
                "required": [
                  "action"
                ]
              },
              "example": {
                "action": "accept",
                "postcode": "6021"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decided.",
            "content": {
              "application/json": {
                "example": {
                  "address_id": "363752",
                  "status": "accepted",
                  "postcode": "6021"
                }
              }
            }
          },
          "400": {
            "description": "The action is not \u0060accept\u0060 or \u0060dismiss\u0060, or accept has no four-digit postcode."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "404": {
            "description": "No open neighbour flag for this address."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/postcode-corrections/review/accounts/{account}/resume": {
      "post": {
        "operationId": "postcodeReviewResume",
        "summary": "Resume a paused account\u0027s postcode corrections",
        "description": "Staff only. Lifts a pause so the account\u0027s new reports are taken again. Its past reports stay rejected. Requires the admin key of a reviewer\u0027s subscription.",
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "description": "The account name, as the review queue\u0027s paused_accounts lists it.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resumed.",
            "content": {
              "application/json": {
                "example": {
                  "account": "copier",
                  "resumed": true
                }
              }
            }
          },
          "400": {
            "description": "No account named."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "Not an admin key, or its account is not a reviewer."
          },
          "404": {
            "description": "The account is not paused."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "usage",
        "summary": "Today\u0027s look-up usage",
        "description": "Returns today\u0027s metered look-up count (UTC) with the plan\u0027s daily limit and monthly buffer. Requires the subscription\u0027s admin key; the address API key and domain tokens are refused. Also served at /v4/usage.",
        "responses": {
          "200": {
            "description": "Today\u0027s usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                },
                "example": {
                  "date": "2026-09-14T00:00:00Z",
                  "usage_today": 42,
                  "daily_limit": 20,
                  "monthly_buffer": 100,
                  "monthly_buffer_used": 22
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/usage/{day}/{month}/{year}": {
      "get": {
        "operationId": "usageForDay",
        "summary": "One day\u0027s look-up usage",
        "description": "Returns the metered look-up count for a single UTC day. Requires the subscription\u0027s admin key. Also served under /v4.",
        "parameters": [
          {
            "name": "day",
            "in": "path",
            "required": true,
            "description": "Day of the month, 1-31.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "Month, 1-12.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "year",
            "in": "path",
            "required": true,
            "description": "Four-digit year.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "That day\u0027s usage.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            }
          },
          "400": {
            "description": "The day, month and year are not a real date."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/usage/from/{fromDay}/{fromMonth}/{fromYear}/to/{toDay}/{toMonth}/{toYear}": {
      "get": {
        "operationId": "usageForRange",
        "summary": "A range of daily look-up usage",
        "description": "Returns one row per UTC day across an inclusive range, newest first. Days with no look-ups are returned as zero rather than omitted. A range may not exceed 366 days. Requires the subscription\u0027s admin key. Also served under /v4.",
        "parameters": [
          {
            "name": "fromDay",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "fromMonth",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "fromYear",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "toDay",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "toMonth",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "toYear",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One row per day, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Usage"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Either end is not a real date, or the range is longer than 366 days."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/subscription/label": {
      "put": {
        "operationId": "renameSubscription",
        "summary": "Rename the subscription",
        "description": "Sets what the subscription is called in the console and in emails. Its name, keys, domain tokens and usage do not change. A blank label puts back the subscription\u0027s own name. Labels must be unique on the account, ignoring case. Requires the subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "What to call the subscription. Blank puts back its own name."
                  }
                }
              },
              "example": {
                "label": "Main site"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription as it is now called.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "The subscription\u0027s identifier. Never changes."
                    },
                    "label": {
                      "type": "string",
                      "description": "What the subscription is called."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The label is too long, or another subscription on the account is already called that."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/connect/token": {
      "post": {
        "operationId": "connectToken",
        "summary": "Exchange a Connect code for a shop\u0027s key",
        "description": "For checkout plugins. After the merchant allows their shop at https://getaddress.nz/connect, the plugin\u0027s server (never a browser) posts the single-use code it was sent back with and its PKCE code_verifier. Answers the API key issued to that shop on the account\u0027s default subscription and, for WooCommerce, a domain token for the shop\u0027s domain. A code works once, for ten minutes. Needs no API key: the code and verifier are the credential.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type",
                  "code",
                  "code_verifier",
                  "client",
                  "redirect_uri"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "authorization_code"
                    ]
                  },
                  "code": {
                    "type": "string",
                    "description": "The code getaddress.nz/connect added to the redirect."
                  },
                  "code_verifier": {
                    "type": "string",
                    "description": "The PKCE verifier whose S256 challenge was sent to getaddress.nz/connect (43 to 128 characters)."
                  },
                  "client": {
                    "type": "string",
                    "enum": [
                      "woocommerce",
                      "shopify"
                    ]
                  },
                  "redirect_uri": {
                    "type": "string",
                    "description": "Exactly the redirect_uri sent to getaddress.nz/connect."
                  }
                }
              },
              "example": {
                "grant_type": "authorization_code",
                "code": "Hk3\u2026",
                "code_verifier": "x9F\u2026",
                "client": "woocommerce",
                "redirect_uri": "https://shop.example.co.nz/wp-admin/admin.php?page=wc-settings\u0026tab=getaddress"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The shop\u0027s credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_key": {
                      "type": "string",
                      "description": "The key issued to this shop. Keep it on the shop\u0027s server."
                    },
                    "domain_token": {
                      "type": "string",
                      "nullable": true,
                      "description": "WooCommerce only: a domain token for the shop\u0027s domain, for its checkout pages."
                    },
                    "subscription": {
                      "type": "string",
                      "description": "The subscription the shop spends against."
                    },
                    "shop": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "api_key": "\u2026",
                  "domain_token": "dtoken_\u2026",
                  "subscription": "main",
                  "shop": "shop.example.co.nz"
                }
              }
            }
          },
          "400": {
            "description": "invalid_grant: the code is unknown, expired, already used, or the verifier, client or redirect_uri does not match."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/connect/revoke": {
      "post": {
        "operationId": "connectRevoke",
        "summary": "Disconnect a shop",
        "description": "A connected shop\u0027s Disconnect: revokes the key it was issued by Connect and every domain token made from it. Only a connection\u0027s own key is accepted; a subscription\u0027s own API and admin keys are refused.",
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "type": "boolean"
                    }
                  }
                },
                "example": {
                  "revoked": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is not a connection\u0027s key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/subscription/auto-upgrade": {
      "put": {
        "operationId": "configureAutoUpgrade",
        "summary": "Switch auto-upgrade on or off",
        "description": "Auto-upgrade is on for every paid subscription unless switched off. When the daily limit is reached with no monthly buffer left, the subscription moves up one plan and the difference is charged to its card straight away; one plan at a time, at most once an hour. Switched off, look-ups are refused at the limit until it resets. Not available on the Free plan. Requires the subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean",
                    "description": "True to move up a plan at the limit, false to stop at the limit instead."
                  }
                }
              },
              "example": {
                "enabled": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The subscription\u0027s auto-upgrade setting as it is now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "The subscription\u0027s identifier."
                    },
                    "enabled": {
                      "type": "boolean",
                      "description": "Whether it moves up a plan when its limit stops it."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body has no enabled, or the subscription is on the Free plan."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/batches": {
      "post": {
        "operationId": "uploadBatch",
        "summary": "Upload a CSV of addresses to clean",
        "description": "Takes a CSV file as the request body, finds its address columns (the headers and a few sample rows are read by an AI service, Anthropic) and returns the batch, ready to run. Nothing is charged. Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "The file\u0027s name, kept for the download.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/csv": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The batch, with the columns found and the price.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            }
          },
          "400": {
            "description": "The file is empty, too big, has too many rows, or the day\u0027s uploads are used."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "operationId": "listBatches",
        "summary": "Your subscription\u0027s batches, newest first",
        "description": "Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "responses": {
          "200": {
            "description": "The batches.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "batches": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Batch"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/batches/{id}": {
      "get": {
        "operationId": "getBatch",
        "summary": "A batch and its progress",
        "description": "rows_done counts up while it runs. A batch paid for on Stripe\u0027s page starts as soon as it is asked for. Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The batch\u0027s id, from POST /batches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            }
          },
          "404": {
            "description": "No batch with that id on this subscription, or it has been deleted."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/batches/{id}/mapping": {
      "put": {
        "operationId": "changeBatchMapping",
        "summary": "Choose the address columns yourself",
        "description": "Replaces the columns found. Every address column, numbered from 0, with its role, in reading order. Only before the batch runs. Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The batch\u0027s id, from POST /batches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchMapping"
              },
              "example": {
                "has_header": true,
                "columns": [
                  {
                    "column": 1,
                    "role": "line"
                  },
                  {
                    "column": 4,
                    "role": "postcode"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The batch with its new columns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            }
          },
          "400": {
            "description": "No columns, a column the file doesn\u0027t have or used twice, an unknown role, or the batch has already run."
          },
          "404": {
            "description": "No batch with that id on this subscription, or it has been deleted."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/batches/{id}/run": {
      "post": {
        "operationId": "runBatch",
        "summary": "Clean every row",
        "description": "A free batch starts at once. Otherwise the response carries checkout_url: the batch starts when it is paid there. Every row is paid for up front and the rows that don\u0027t match are refunded when it finishes. Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The batch\u0027s id, from POST /batches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The batch: running, or awaiting_payment with checkout_url.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            }
          },
          "400": {
            "description": "The batch has no address columns or has already run, or paying isn\u0027t available."
          },
          "404": {
            "description": "No batch with that id on this subscription, or it has been deleted."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/batches/{id}/result": {
      "get": {
        "operationId": "getBatchResult",
        "summary": "Download the cleaned CSV",
        "description": "Your columns as they were, then ga_status, ga_id, ga_address, ga_level, ga_unit, ga_number, ga_street, ga_suburb, ga_state, ga_postcode, ga_latitude, ga_longitude and ga_candidates. Requires your subscription\u0027s admin key; the address API key and domain tokens are refused.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The batch\u0027s id, from POST /batches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The cleaned file.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "No such batch, or it isn\u0027t done yet."
          },
          "401": {
            "description": "Missing or invalid API key."
          },
          "403": {
            "description": "The key is valid but is not the subscription\u0027s admin key."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/api/info": {
      "get": {
        "operationId": "apiInfo",
        "summary": "Self-describing manifest for coding agents",
        "description": "Returns the API\u0027s name, description, OpenAPI and reference URLs, how to authenticate and the error code dictionary. No key needed.",
        "security": [],
        "responses": {
          "200": {
            "description": "The manifest.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiInfo"
                }
              }
            }
          }
        }
      }
    },
    "/api/examples": {
      "get": {
        "operationId": "apiExamples",
        "summary": "Worked request and response examples",
        "description": "Returns copy-pasteable examples of every endpoint and the common errors, written for coding agents. No key needed.",
        "security": [],
        "responses": {
          "200": {
            "description": "The examples.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiExamples"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "operationId": "apiCatalog",
        "summary": "API discovery catalog",
        "description": "The entry point for automated tooling, following the IETF API Catalog draft: a linkset pointing at the OpenAPI description, the interactive reference, /api/info and /api/examples. No key needed.",
        "security": [],
        "responses": {
          "200": {
            "description": "The catalog.",
            "content": {
              "application/linkset\u002Bjson": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCatalog"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "RateLimited": {
        "description": "Rate limit exceeded.",
        "headers": {
          "Retry-After": {
            "description": "Seconds until a successful retry can be made.",
            "schema": {
              "type": "integer"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api-key",
        "description": "API key (or a domain token for browser use) as a query parameter. /usage takes the subscription\u0027s admin key here instead."
      }
    },
    "schemas": {
      "Suggestions": {
        "type": "object",
        "required": [
          "suggestions"
        ],
        "properties": {
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Suggestion"
            }
          },
          "fallback": {
            "$ref": "#/components/schemas/SuggestionsFallback"
          }
        }
      },
      "SuggestionsFallback": {
        "type": "object",
        "description": "Only present when there are no suggestions, the request used a domain token, and the subscription has the Google Places fallback switched on. The JavaScript Autocomplete uses it to search Google for businesses and places from the browser.",
        "required": [
          "provider",
          "key"
        ],
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "google_places"
            ]
          },
          "key": {
            "type": "string",
            "description": "The customer\u0027s own Google API key, as saved in the console."
          }
        }
      },
      "Suggestion": {
        "type": "object",
        "required": [
          "address",
          "url",
          "id"
        ],
        "properties": {
          "address": {
            "type": "string",
            "description": "The suggestion display text, e.g. \u0022169 Lambton Quay, Wellington Central, Wellington 6011\u0022."
          },
          "url": {
            "type": "string",
            "description": "Relative URL that resolves this suggestion, e.g. \u0022/get/363752\u0022."
          },
          "id": {
            "type": "string",
            "description": "The address\u0027s LINZ address_id, e.g. \u0022363752\u0022. Passed to /get/{id}."
          }
        }
      },
      "NearestAddresses": {
        "type": "object",
        "required": [
          "suggestions"
        ],
        "properties": {
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NearestAddress"
            }
          }
        }
      },
      "NearestAddress": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Suggestion"
          },
          {
            "type": "object",
            "required": [
              "distance"
            ],
            "properties": {
              "distance": {
                "type": "integer",
                "format": "int64",
                "description": "Straight-line distance from the point to the address\u0027s position, in whole metres."
              }
            }
          }
        ]
      },
      "Address": {
        "type": "object",
        "description": "A New Zealand address from LINZ\u0027s NZ Addresses. Every string field is present on every address, empty when that address has no value for it.",
        "required": [
          "id",
          "address_id",
          "address_label",
          "address_status",
          "locality_name",
          "postcode"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "LINZ\u0027s address_id; the same value as the id passed to /get/{id}."
          },
          "address_id": {
            "type": "string",
            "description": "LINZ\u0027s address_id, e.g. \u0022363752\u0022."
          },
          "address_label": {
            "type": "string",
            "description": "The one-line label, e.g. \u002212 Queen Street, Auckland Central, Auckland 1010\u0022. The same text a suggestion shows."
          },
          "address_status": {
            "type": "string",
            "description": "\u0022current\u0022, or \u0022retired\u0022 when LINZ has since withdrawn the address. A retired address still resolves, so an id you stored keeps working, but it is no longer suggested.",
            "enum": [
              "current",
              "retired"
            ]
          },
          "flat_number": {
            "type": "string",
            "description": "The unit, as LINZ writes it (\u00222\u0022, \u00227A\u0022, \u0022G04\u0022). Empty when none."
          },
          "number_first": {
            "type": "string",
            "description": "The street number, or the first of a range."
          },
          "number_last": {
            "type": "string",
            "description": "The last street number of a range (\u002256\u0022 of 48-56 Queen Street). Empty for a single number."
          },
          "number_suffix": {
            "type": "string",
            "description": "The letter after the street number (\u0022A\u0022 of 12A). Empty when none."
          },
          "full_road_name": {
            "type": "string",
            "description": "The road\u0027s whole name, type and suffix included, e.g. \u0022Customs Street East\u0022."
          },
          "locality_name": {
            "type": "string",
            "description": "The suburb or locality, e.g. \u0022\u014Ct\u0101huhu\u0022."
          },
          "town_city": {
            "type": "string",
            "description": "The town or city, e.g. \u0022Auckland\u0022. Empty when LINZ gives none."
          },
          "territorial_authority": {
            "type": "string",
            "description": "The district or city council, e.g. \u0022Selwyn District\u0022."
          },
          "postcode": {
            "type": "string",
            "description": "The unofficial four-digit postcode, e.g. \u00226011\u0022. Empty when none could be assigned. Not NZ Post\u0027s: see postcode_source."
          },
          "postcode_source": {
            "type": "string",
            "description": "How the postcode was assigned: \u0022road\u0022 (from the road), \u0022suburb (single)\u0022 (the suburb has one postcode), \u0022suburb (majority)\u0022 (most of the suburb\u0027s addresses have it; lower confidence), \u0022none\u0022 (no postcode; postcode is \u0022\u0022), or, from customer corrections, \u0022corrected\u0022 and \u0022corrected (road)\u0022.",
            "enum": [
              "road",
              "suburb (single)",
              "suburb (majority)",
              "none",
              "corrected",
              "corrected (road)"
            ]
          },
          "coordinates": {
            "type": "object",
            "nullable": true,
            "description": "The LINZ address point (WGS84). Null when the address carries no coordinates.",
            "required": [
              "latitude",
              "longitude"
            ],
            "properties": {
              "latitude": {
                "type": "number",
                "format": "double"
              },
              "longitude": {
                "type": "number",
                "format": "double"
              }
            }
          }
        }
      },
      "AutocompleteOptions": {
        "type": "object",
        "description": "Optional body for the POST autocomplete variant. All properties are optional; an empty body behaves exactly like the GET.",
        "properties": {
          "top": {
            "type": "integer",
            "default": 6,
            "maximum": 6,
            "description": "Number of suggestions to return (max 6)."
          },
          "template": {
            "type": "string",
            "default": "{formatted_address}",
            "description": "Suggestion text template, e.g. \u0022{formatted_address}\u0022. \u0060{name,prefix,suffix}\u0060 wraps a non-empty field with the given prefix/suffix. Available fields: formatted_address, locality (or suburb), suburb_locality, town_city, postcode, postcode_source."
          },
          "filter": {
            "type": "object",
            "description": "Limits suggestions to matching addresses.",
            "properties": {
              "town_city": {
                "type": "string",
                "description": "Town or city, e.g. \u0022Auckland\u0022."
              },
              "locality": {
                "type": "string",
                "description": "Suburb or locality, e.g. \u0022\u014Ct\u0101huhu\u0022."
              },
              "postcode": {
                "type": "string",
                "description": "4-digit postcode."
              },
              "radius": {
                "type": "object",
                "description": "Only suggest addresses within km of the point.",
                "properties": {
                  "km": {
                    "type": "number",
                    "description": "Max distance from latitude/longitude in kilometres."
                  },
                  "latitude": {
                    "type": "number"
                  },
                  "longitude": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "location": {
            "type": "object",
            "description": "Prefer suggestions closer to this point.",
            "properties": {
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              }
            }
          },
          "ip_address": {
            "type": "string",
            "description": "Your end user\u0027s IP address, to prefer suggestions near them. Read only on an API-key request; a domain-token request uses the visitor\u0027s own address."
          }
        }
      },
      "LocationSuggestions": {
        "type": "object",
        "required": [
          "suggestions"
        ],
        "properties": {
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LocationSuggestion"
            }
          }
        }
      },
      "LocationSuggestion": {
        "type": "object",
        "required": [
          "location",
          "url",
          "id"
        ],
        "properties": {
          "location": {
            "type": "string",
            "description": "The place as it should be shown: suburb, then town when it differs, then postcode, e.g. \u0022Normanby, H\u0101wera 4614\u0022 or \u0022Rolleston 7614\u0022."
          },
          "url": {
            "type": "string",
            "description": "Relative URL that resolves this place, e.g. \u0022/get-location/Normanby%7CH%C4%81wera%7C4614\u0022."
          },
          "id": {
            "type": "string",
            "description": "The place\u0027s location id: suburb, town and postcode joined by \u0022|\u0022, e.g. \u0022Normanby|H\u0101wera|4614\u0022. Passed to /get-location/{id}, URL-encoded."
          }
        }
      },
      "NearestLocations": {
        "type": "object",
        "required": [
          "suggestions"
        ],
        "properties": {
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NearestLocation"
            }
          }
        }
      },
      "NearestLocation": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LocationSuggestion"
          },
          {
            "type": "object",
            "required": [
              "distance"
            ],
            "properties": {
              "distance": {
                "type": "integer",
                "format": "int64",
                "description": "Straight-line distance from the point to the place\u0027s centre, in whole metres."
              }
            }
          }
        ]
      },
      "Place": {
        "type": "object",
        "required": [
          "id",
          "location",
          "locality_name",
          "town_city",
          "postcode"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The place\u0027s location id, e.g. \u0022Normanby|H\u0101wera|4614\u0022."
          },
          "location": {
            "type": "string",
            "description": "The label, e.g. \u0022Normanby, H\u0101wera 4614\u0022."
          },
          "locality_name": {
            "type": "string",
            "description": "The suburb or locality, as LINZ names it, e.g. \u0022Normanby\u0022."
          },
          "town_city": {
            "type": "string",
            "description": "The town or city, e.g. \u0022H\u0101wera\u0022."
          },
          "territorial_authority": {
            "type": "string",
            "description": "The district or city council, e.g. \u0022South Taranaki District\u0022."
          },
          "postcode": {
            "type": "string",
            "description": "The unofficial four-digit postcode, e.g. \u00224614\u0022 or \u00220110\u0022. Empty when none could be assigned."
          },
          "coordinates": {
            "type": "object",
            "nullable": true,
            "description": "The centre of the place (WGS84): the mean position of its addresses. It can fall outside a crescent-shaped suburb. Null only if the place has no position.",
            "required": [
              "latitude",
              "longitude"
            ],
            "properties": {
              "latitude": {
                "type": "number",
                "format": "double"
              },
              "longitude": {
                "type": "number",
                "format": "double"
              }
            }
          }
        }
      },
      "LocationOptions": {
        "type": "object",
        "description": "Optional body for the POST location variant. All properties are optional; an empty body behaves exactly like the GET.",
        "properties": {
          "top": {
            "type": "integer",
            "default": 6,
            "maximum": 20,
            "description": "Number of suggestions to return (max 20)."
          },
          "filter": {
            "type": "object",
            "description": "Limits suggestions to matching places.",
            "properties": {
              "town_city": {
                "type": "string",
                "description": "Town or city, e.g. \u0022H\u0101wera\u0022."
              },
              "postcode": {
                "type": "string",
                "description": "4-digit postcode."
              },
              "radius": {
                "type": "object",
                "description": "Only suggest places whose centre is within km of the point.",
                "properties": {
                  "km": {
                    "type": "number",
                    "description": "Max distance from latitude/longitude in kilometres."
                  },
                  "latitude": {
                    "type": "number"
                  },
                  "longitude": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "location": {
            "type": "object",
            "description": "Prefer places closer to this point. Nothing is excluded.",
            "properties": {
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              }
            }
          },
          "ip_address": {
            "type": "string",
            "description": "Your end user\u0027s IP address, to prefer places near them. Read only on an API-key request."
          }
        }
      },
      "TypeaheadValues": {
        "type": "array",
        "description": "Completed values: plain strings, as LINZ writes them (macrons included).",
        "items": {
          "type": "string"
        }
      },
      "TypeaheadOptions": {
        "type": "object",
        "description": "Optional body for the POST typeahead variant. All properties are optional; an empty body behaves exactly like the GET.",
        "properties": {
          "top": {
            "type": "integer",
            "default": 6,
            "maximum": 20,
            "description": "Number of values to return (max 20)."
          },
          "search": {
            "type": "array",
            "description": "The fields to complete. Omitted, every field is completed alike.",
            "items": {
              "type": "string",
              "enum": [
                "street",
                "locality",
                "town_city",
                "postcode"
              ]
            }
          },
          "filter": {
            "type": "object",
            "description": "Only values held by addresses matching every field set.",
            "properties": {
              "town_city": {
                "type": "string",
                "description": "Town or city as LINZ writes it, e.g. \u0022H\u0101wera\u0022."
              },
              "locality": {
                "type": "string",
                "description": "Suburb or locality as LINZ writes it, e.g. \u0022Normanby\u0022."
              },
              "postcode": {
                "type": "string",
                "description": "4-digit postcode."
              }
            }
          },
          "same": {
            "type": "boolean",
            "default": true,
            "description": "False drops a lone value that only repeats the term."
          }
        }
      },
      "ValidateCandidates": {
        "type": "object",
        "required": [
          "candidates"
        ],
        "properties": {
          "candidates": {
            "type": "array",
            "description": "The candidates\u0027 LINZ address_ids, best first. Pass one to /get/{id}.",
            "items": {
              "type": "string"
            }
          },
          "primary_secondary": {
            "type": "string",
            "enum": [
              "PRIMARY"
            ],
            "description": "Present only when the line names one building whose LINZ addresses are all its units, and gives no unit: the candidates are those units, and only the unit is missing. The same field and value that marks a building with units on getaddress.io\u0027s (AU) answer."
          }
        }
      },
      "Distance": {
        "type": "object",
        "required": [
          "metres"
        ],
        "properties": {
          "metres": {
            "type": "integer",
            "format": "int64",
            "description": "The straight-line (great-circle) distance in whole metres. Not a driving distance."
          }
        }
      },
      "PostcodeCorrectionRequest": {
        "type": "object",
        "description": "The postcode the address should have.",
        "required": [
          "postcode"
        ],
        "properties": {
          "postcode": {
            "type": "string",
            "description": "The correct four-digit postcode, e.g. \u00224614\u0022. Must be one some New Zealand address already has."
          },
          "source": {
            "type": "string",
            "enum": [
              "user",
              "customer"
            ],
            "default": "user",
            "description": "Who is correcting it: \u0022user\u0022 when a person changed the postcode of their own address (the default), or \u0022customer\u0022 when your own staff did, e.g. from returned mail."
          },
          "note": {
            "type": "string",
            "maxLength": 200,
            "description": "Optional, up to 200 characters: how you know, e.g. \u0022returned mail\u0022."
          }
        }
      },
      "PostcodeCorrectionResponse": {
        "type": "object",
        "description": "A correction as its reporter sees it.",
        "required": [
          "id",
          "address_id",
          "postcode",
          "previous_postcode",
          "source",
          "status",
          "created"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The correction\u0027s id."
          },
          "address_id": {
            "type": "string",
            "description": "The LINZ address_id it corrects."
          },
          "postcode": {
            "type": "string",
            "description": "The postcode reported."
          },
          "previous_postcode": {
            "type": "string",
            "description": "The postcode the address had when it was reported."
          },
          "source": {
            "type": "string",
            "enum": [
              "user",
              "customer"
            ],
            "description": "Who reported it."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "applied",
              "superseded",
              "rejected"
            ],
            "description": "\u0022pending\u0022 until the weekly rebuild, then \u0022applied\u0022, \u0022superseded\u0022 or \u0022rejected\u0022."
          },
          "created": {
            "type": "string",
            "format": "date-time",
            "description": "When it was reported."
          }
        }
      },
      "PostcodeCorrectionsResponse": {
        "type": "object",
        "required": [
          "corrections"
        ],
        "properties": {
          "corrections": {
            "type": "array",
            "description": "Newest first.",
            "items": {
              "$ref": "#/components/schemas/PostcodeCorrectionResponse"
            }
          }
        }
      },
      "Usage": {
        "type": "object",
        "description": "One UTC day\u0027s metered look-ups for a subscription.",
        "required": [
          "date",
          "usage_today",
          "daily_limit",
          "monthly_buffer",
          "monthly_buffer_used"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date-time",
            "description": "The UTC day this row covers."
          },
          "usage_today": {
            "type": "integer",
            "format": "int64",
            "description": "Metered look-ups on that day."
          },
          "daily_limit": {
            "type": "integer",
            "description": "The plan\u0027s daily allowance. 2147483647 when the plan has no daily limit."
          },
          "monthly_buffer": {
            "type": "integer",
            "description": "The plan\u0027s monthly overflow allowance. 0 when the plan has none."
          },
          "monthly_buffer_used": {
            "type": "integer",
            "format": "int64",
            "description": "How much of the buffer the day\u0027s whole calendar month has used, so it repeats on every row of a month."
          }
        }
      },
      "BatchMapping": {
        "type": "object",
        "required": [
          "has_header",
          "columns"
        ],
        "properties": {
          "has_header": {
            "type": "boolean"
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "column",
                "role"
              ],
              "properties": {
                "column": {
                  "type": "integer",
                  "description": "The column\u0027s position, from 0."
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "unit",
                    "number",
                    "street",
                    "line",
                    "suburb",
                    "postcode"
                  ]
                },
                "header": {
                  "type": "string",
                  "nullable": true,
                  "description": "The column\u0027s header, in responses."
                }
              }
            }
          }
        }
      },
      "Batch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "file_name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ready",
              "awaiting_payment",
              "running",
              "done",
              "failed"
            ]
          },
          "rows": {
            "type": "integer",
            "description": "Rows to clean, not counting the header."
          },
          "mapping": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BatchMapping"
              }
            ],
            "nullable": true
          },
          "mapping_reason": {
            "type": "string",
            "description": "Why these columns, in a sentence."
          },
          "needs_review": {
            "type": "boolean",
            "description": "Check the columns before running: the AI was unsure, or few sample rows matched."
          },
          "price_cents": {
            "type": "integer",
            "nullable": true,
            "description": "What running it costs up front, in NZD cents. Unmatched rows are refunded."
          },
          "free": {
            "type": "boolean"
          },
          "checkout_url": {
            "type": "string",
            "nullable": true,
            "description": "Where to pay, after run."
          },
          "rows_done": {
            "type": "integer"
          },
          "matched": {
            "type": "integer"
          },
          "ambiguous": {
            "type": "integer"
          },
          "not_found": {
            "type": "integer"
          },
          "invalid": {
            "type": "integer"
          },
          "refunded_cents": {
            "type": "integer"
          },
          "created": {
            "type": "string",
            "format": "date-time"
          },
          "expires": {
            "type": "string",
            "format": "date-time",
            "description": "When the batch and its files are deleted."
          }
        }
      },
      "ApiInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "openapi_url": {
            "type": "string"
          },
          "documentation_url": {
            "type": "string"
          },
          "examples_url": {
            "type": "string"
          },
          "authentication": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "example": "api-key"
              },
              "description": {
                "type": "string"
              }
            }
          },
          "error_codes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "example": "unauthorized"
                },
                "status": {
                  "type": "integer",
                  "example": 401
                },
                "description": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ApiExamples": {
        "type": "object",
        "properties": {
          "examples": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "example": "autocomplete"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "method": {
                  "type": "string",
                  "example": "GET"
                },
                "path": {
                  "type": "string",
                  "example": "/autocomplete/169%20lambton?api-key=YOUR-API-KEY\u0026top=6"
                },
                "request_body": {
                  "type": "object",
                  "nullable": true
                },
                "response_status": {
                  "type": "integer",
                  "example": 200
                },
                "response_example": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "ApiCatalog": {
        "type": "object",
        "properties": {
          "linkset": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "anchor": {
                  "type": "string"
                },
                "rel": {
                  "type": "string",
                  "example": "service-desc"
                },
                "href": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}