# Mapbase Engine API

- **OpenAPI Version:** `3.1.0`
- **API Version:** `0.0.0`

The **Mapbase Engine** is the public HTTP API for Mapbase products.

This reference is generated from the same Zod/OpenAPI contracts that the engine uses at runtime.

## Base URL & versioning

All stable API routes live under `/v1`. Utility routes (`/health`, `/redis-health`, `/layers`, `/openapi.json`, `/reference`) sit outside the versioned contract and do not require authentication.

`/v1` is a stable contract: we add fields, routes, and optional parameters without bumping the version, but we never remove a field or make a breaking change to an existing one within `/v1`. A breaking change ships under a new prefix (`/v2`). Clients should ignore unknown response fields so additive changes are non-breaking for them.

Send an `x-sdk-version` header (the official SDK sets it automatically) so we can attribute traffic and warn about outdated clients. When a route is slated for removal it is first marked `deprecated` in this spec and serves a `Deprecation` header (and, once a removal date is set, a `Sunset` header) for at least one deprecation window before it is retired.

## Layers

Registry data is grouped into three **layers**: `locations`, `postcodes`, and `zones`. The `layer` field appears on autocomplete hits, boundary routes, and the optional `layers` query parameter on several endpoints. **GET /layers** lists each layer with record counts and covered countries (sourced from `search_registry`).

Two Postgres materialized views back different read paths. **`search_registry`** holds searchable rows for locations, postcodes, and zones, with trigram-friendly text fields and ranking metadata; **GET /v1/autocomplete** and per-layer autocomplete routes query it. **`point_layers`** holds polygon-backed rows only (`locations`, `zones`) with full geometry for point-in-polygon tests; **GET /v1/points/resolve** queries it. Postcodes live in `search_registry` but not `point_layers` (they have no own boundary polygon), so resolve accepts `layers=locations|zones` only — use the postcode routes for postal lookups. By default, resolve uses `layers=locations,zones`. With `include=postcodes`, resolve embeds `anchor.postcode` (string or `null`) from the input coordinates plus the linked-code list on `anchor.postcodes`.

## Custom zones

Published custom zones are read-only at **GET /v1/zones**. Customer writes use **POST /v1/zone-submissions** (draft → submit → admin review); approved submissions are published to the zones registry. The same workflow is available in the dashboard at [dashboard.mapbase.dev](https://dashboard.mapbase.dev).

## Canonical registry IDs

Registry rows expose a canonical **`id`** prefixed by layer: `mb_loc_`, `mb_zon_`, `mb_lau_`, `mb_cod_`. Each is deterministic URL-safe base64url of the upstream key (postcodes encode Eurostat `pc_cntr`). Responses always return `mb_*` as `id`; upstream ingestion keys are not included in JSON bodies. Route path and query parameters may still accept legacy upstream keys where noted per route. LAU rows expose `gisco_id`; postcodes expose `code` for display. Location path and hierarchy filters use canonical `mb_loc_*` ids (including `parent_id` on location nodes).

## Authentication

Every `/v1` route requires an API key, sent in the `x-api-key` header. Requests without a valid key receive `401` (`auth_missing_key` / `auth_invalid_key`). The utility routes (`/health`, `/redis-health`, `/layers`, `/openapi.json`, `/reference`) are unauthenticated. For local testing in the Scalar reference UI, set `REFERENCE_API_KEY` in your `.env` to pre-fill the key on every `/v1` endpoint. Provider passthrough routes also accept `x-google-api-key` and `x-geoapify-api-key`; pre-fill those in Scalar with `REFERENCE_GOOGLE_API_KEY` and `REFERENCE_GEOAPIFY_API_KEY` (engine `/reference`) or `REFERENCE_GOOGLE_API_KEY` / `GEOAPIFY_API_KEY` (dashboard `/api`).

## Rate limits & credits

Each API key is rate limited per second (burst) and per billing period (quota). Successful `/v1` responses include `X-Mapbase-Credits` with the credits charged for that request. Quota headers use the IETF-draft `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy` fields; `429` responses add `Retry-After`. The base path cost is documented on each operation as the `x-mapbase-credits` OpenAPI extension — use the [playgrounds](https://mapbase.dev/playground) to see request-aware costs live. When you exceed your included volume, requests are blocked until you upgrade or the billing period resets.

## Errors

Every error response follows:

```json
{
  "error": {
    "code": "not_found",
    "message": "Human-readable explanation.",
    "request_id": "..."
  }
}
```

## Servers

- **URL:** `https://api.mapbase.dev`
  - **Description:** Production

## Operations

### Liveness probe

- **Method:** `GET`
- **Path:** `/health`
- **Tags:** health

Unversioned health check for load balancers and uptime monitors. Does not require an API key.

#### Responses

##### Status: 200 Service is up.

###### Content-Type: application/json

- **`environment` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"ok"`

- **`uptime_ms` (required)**

  `integer`

- **`version` (required)**

  `string`

**Example:**

```json
{
  "status": "ok",
  "uptime_ms": 1,
  "version": "",
  "environment": ""
}
```

### Redis connectivity probe

- **Method:** `GET`
- **Path:** `/redis-health`
- **Tags:** health

Unversioned Redis health check for ops debugging. Does not require an API key. Returns 503 when Redis is unreachable.

#### Responses

##### Status: 200 Redis is reachable.

###### Content-Type: application/json

**One of:**

- **`ip_rules_loaded` (required)**

  `boolean`

- **`ratelimit_enabled` (required)**

  `boolean`

- **`redis` (required)**

  `object`

  - **`host` (required)**

    `string`

  - **`latency_ms` (required)**

    `integer`

  - **`reachable` (required)**

    `boolean`, possible values: `true`

- **`status` (required)**

  `string`, possible values: `"ok"`

* **`ip_rules_loaded` (required)**

  `null`

* **`ratelimit_enabled` (required)**

  `boolean`

* **`redis` (required)**

  `object`

  - **`error` (required)**

    `string`

  - **`host` (required)**

    `string`

  - **`latency_ms` (required)**

    `null`

  - **`reachable` (required)**

    `boolean`, possible values: `false`

* **`status` (required)**

  `string`, possible values: `"error"`

**Example:**

```json
{
  "status": "ok",
  "redis": {
    "reachable": true,
    "host": "",
    "latency_ms": 0
  },
  "ratelimit_enabled": true,
  "ip_rules_loaded": true
}
```

##### Status: 503 Redis is unreachable.

###### Content-Type: application/json

**One of:**

- **`ip_rules_loaded` (required)**

  `boolean`

- **`ratelimit_enabled` (required)**

  `boolean`

- **`redis` (required)**

  `object`

  - **`host` (required)**

    `string`

  - **`latency_ms` (required)**

    `integer`

  - **`reachable` (required)**

    `boolean`, possible values: `true`

- **`status` (required)**

  `string`, possible values: `"ok"`

* **`ip_rules_loaded` (required)**

  `null`

* **`ratelimit_enabled` (required)**

  `boolean`

* **`redis` (required)**

  `object`

  - **`error` (required)**

    `string`

  - **`host` (required)**

    `string`

  - **`latency_ms` (required)**

    `null`

  - **`reachable` (required)**

    `boolean`, possible values: `false`

* **`status` (required)**

  `string`, possible values: `"error"`

**Example:**

```json
{
  "status": "ok",
  "redis": {
    "reachable": true,
    "host": "",
    "latency_ms": 0
  },
  "ratelimit_enabled": true,
  "ip_rules_loaded": true
}
```

### List registry layers

- **Method:** `GET`
- **Path:** `/layers`
- **Tags:** layers

Unversioned registry layer counts. Does not require an API key.

#### Responses

##### Status: 200 Layer counts from search\_registry.

###### Content-Type: application/json

- **`layers` (required)**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`label` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`countries`**

    `array`

    **Items:**

    `string`

- **`breakdown`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level`**

    `number`

- **`byLayerCountry`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

- **`countries`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

**Example:**

```json
{
  "layers": [
    {
      "layer": "locations",
      "label": "",
      "count": 0,
      "countries": [
        ""
      ]
    }
  ],
  "countries": [
    {
      "country": "",
      "count": 0
    }
  ],
  "byLayerCountry": [
    {
      "layer": "locations",
      "country": "",
      "count": 0
    }
  ],
  "breakdown": [
    {
      "layer": "locations",
      "country": "",
      "kind": null,
      "level": 0,
      "count": 0
    }
  ]
}
```

### List locations

- **Method:** `GET`
- **Path:** `/v1/locations`
- **Tags:** locations

List and filter locations. Supports text search via `q`, but typeahead belongs to `/v1/autocomplete`.

Examples:

- `GET /v1/locations?country=PT&kind=municipality`
- `GET /v1/locations?q=lisboa&country=PT`

#### Parameters

##### `limit`

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `kind`

- **In:** `query`

`string`, possible values: `"arrondissement", "autonomous_city", "autonomous_region", "comarca", "continent", "country", "country_division", "county", "department", "district", "external_region", "island", "municipality", "microstate", "neighborhood", "overseas_department", "parish", "province", "region", "town", "ward"`

##### `parent_id`

- **In:** `query`

`string`

##### `level`

- **In:** `query`

`number`

##### `q`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 A page of locations.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get location hierarchy

- **Method:** `GET`
- **Path:** `/v1/locations/{identifier}/relations`
- **Tags:** locations

Navigate parent, children, siblings, and ancestors for a location.

Default `relations=parent,children,ancestors`. Use `include` for geometry on nodes only.

Example: `GET /v1/locations/mb_loc_MC1FVS1QVC0xMS0wNg/relations?relations=children,ancestors`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `limit`

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `offset`

- **In:** `query`

`[ "integer", "null" ]`

##### `country`

- **In:** `query`

`string`

##### `relations`

- **In:** `query`

**Array of:**

`string`, possible values: `"parent", "children", "siblings", "ancestors"`

##### `kind`

- **In:** `query`

**Array of:**

`string`, possible values: `"arrondissement", "autonomous_city", "autonomous_region", "comarca", "continent", "country", "country_division", "county", "department", "district", "external_region", "island", "municipality", "microstate", "neighborhood", "overseas_department", "parish", "province", "region", "town", "ward"`

##### `level`

- **In:** `query`

**Array of:**

`number`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 Selected location relations.

###### Content-Type: application/json

- **`ancestors` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`children` (required)**

  `object`

  - **`data` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

- **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`parent` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`siblings` (required)**

  `object`

  - **`data` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

**Example:**

```json
{
  "location": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "parent": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "children": {
    "data": [
      {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    ],
    "meta": {
      "limit": 1,
      "next_cursor": null
    }
  },
  "siblings": {
    "data": [
      {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    ],
    "meta": {
      "limit": 1,
      "next_cursor": null
    }
  },
  "ancestors": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ]
}
```

##### Status: 400 Invalid query or ambiguous URI.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Location not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Duplicate uri rows.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get location boundary

- **Method:** `GET`
- **Path:** `/v1/locations/{identifier}/boundary`
- **Tags:** locations

Polygon geometry for a location. Accepts canonical `mb_loc_*` id only (no URI).

Example: `GET /v1/locations/mb_loc_MC1FVS1QVC0xMS0wNg/boundary?simplify=0.001&srid=4326`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `simplify`

- **In:** `query`

`[ "number", "null" ]`

##### `srid`

- **In:** `query`

`[ "integer", "null" ]`

#### Responses

##### Status: 200 GeoJSON boundary for the location.

###### Content-Type: application/json

- **`bbox` (required)**

  `array`

- **`geometry` (required)**

  `object`

- **`id` (required)**

  `string`

- **`layer` (required)**

  `string`, possible values: `"locations", "postcodes", "zones"`

- **`srid` (required)**

  `integer`

**Example:**

```json
{
  "id": "",
  "layer": "locations",
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "bbox": [],
  "srid": 1
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Location or boundary not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### List location zones

- **Method:** `GET`
- **Path:** `/v1/locations/{identifier}/zones`
- **Tags:** locations

Returns active zones anchored to the location (`search_registry.parent_id` = location `mb_loc_*` id).

Example: `GET /v1/locations/mb_loc_MC1FVS1QVC0xMS0wNg/zones`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `limit`

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `offset`

- **In:** `query`

`[ "integer", "null" ]`

##### `kind`

- **In:** `query`

**Array of:**

`string`, possible values: `"arrondissement", "autonomous_city", "autonomous_region", "comarca", "continent", "country", "country_division", "county", "department", "district", "external_region", "island", "municipality", "microstate", "neighborhood", "overseas_department", "parish", "province", "region", "town", "ward"`

##### `level`

- **In:** `query`

**Array of:**

`number`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

##### `country`

- **In:** `query`

`string`

#### Responses

##### Status: 200 Zones anchored to the location.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`location` (required)**

    `object`

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`location_id` (required)**

    `string | null`

  - **`name` (required)**

    `string`

  - **`status` (required)**

    `string`, possible values: `"active", "inactive"`

  - **`uri` (required)**

    `string`

  - **`centroid`**

    `array | null`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "name": "",
      "uri": "",
      "kind": "",
      "country": "",
      "status": "active",
      "location_id": null,
      "location": {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      },
      "centroid": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Location not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Duplicate uri rows.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get location

- **Method:** `GET`
- **Path:** `/v1/locations/{identifier}`
- **Tags:** locations

Fetch one location by canonical `mb_loc_*` id, upstream ingestion id, or URL-encoded URI.

Optional `parent=true` and `hierarchy=true` embed the immediate parent and depth-keyed ancestor chain. Use `include` for geometry on returned nodes; `postcodes` embeds Eurostat codes linked to this location and its subdivisions.

Examples:

- `GET /v1/locations/mb_loc_MC1FVS1QVC0xMS0wNg`
- `GET /v1/locations/0-EU-PT-11-06?parent=true&hierarchy=true`
- `GET /v1/locations/lisboa?country=PT&include=postcodes`
- `GET /v1/locations/santa-maria-maior%2Fbaixa?country=PT`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `country`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines", "postcodes"`

##### `parent`

- **In:** `query`

`[ "boolean", "null" ]`

##### `hierarchy`

- **In:** `query`

`[ "boolean", "null" ]`

#### Responses

##### Status: 200 A single location.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`has_boundary` (required)**

  `boolean`

- **`id` (required)**

  `string`

- **`is_final` (required)**

  `boolean`

- **`kind` (required)**

  `string`

- **`layer` (required)**

  `string`, possible values: `"locations", "postcodes", "zones"`

- **`level` (required)**

  `number`

- **`name` (required)**

  `string`

- **`parent_id` (required)**

  `string | null`

- **`uri` (required)**

  `string | null`

- **`bbox`**

  `array | null`

- **`centroid`**

  `array | null`

- **`hierarchy`**

  `object`

- **`label`**

  `string`

- **`parent`**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`polylines`**

  `array`

  **Items:**

  `string`

- **`postcodes`**

  `array`

  **Items:**

  `string`

**Example:**

```json
{
  "id": "mb_loc_MC1FVS1QVC0xMS0wNg",
  "layer": "locations",
  "kind": "municipality",
  "country": "PT",
  "name": "Lisboa",
  "uri": "lisboa",
  "parent_id": "mb_loc_MC1FVS1QVC0xMQ",
  "level": 4,
  "is_final": false,
  "has_boundary": true,
  "parent": {
    "id": "mb_loc_MC1FVS1QVC0xMQ",
    "layer": "locations",
    "kind": "district",
    "country": "PT",
    "name": "Lisboa distrito",
    "uri": "lisboa-distrito",
    "parent_id": "mb_loc_MC1FVS1QVC1DT05U",
    "level": 3,
    "is_final": false,
    "has_boundary": true
  },
  "hierarchy": {
    "1": {
      "id": "mb_loc_MC1FVS1QVA",
      "layer": "locations",
      "kind": "country",
      "country": "PT",
      "name": "Portugal",
      "uri": "pt",
      "parent_id": null,
      "level": 1,
      "is_final": false,
      "has_boundary": true
    },
    "2": {
      "id": "mb_loc_MC1FVS1QVC1DT05U",
      "layer": "locations",
      "kind": "continent",
      "country": "PT",
      "name": "Portugal (continente)",
      "uri": "portugal-continent",
      "parent_id": "mb_loc_MC1FVS1QVA",
      "level": 2,
      "is_final": false,
      "has_boundary": true
    },
    "3": {
      "id": "mb_loc_MC1FVS1QVC0xMQ",
      "layer": "locations",
      "kind": "district",
      "country": "PT",
      "name": "Lisboa distrito",
      "uri": "lisboa-distrito",
      "parent_id": "mb_loc_MC1FVS1QVC1DT05U",
      "level": 3,
      "is_final": false,
      "has_boundary": true
    },
    "4": {
      "id": "mb_loc_MC1FVS1QVC0xMS0wNg",
      "layer": "locations",
      "kind": "municipality",
      "country": "PT",
      "name": "Lisboa",
      "uri": "lisboa",
      "parent_id": "mb_loc_MC1FVS1QVC0xMQ",
      "level": 4,
      "is_final": false,
      "has_boundary": true
    }
  }
}
```

##### Status: 400 Ambiguous URI without country.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Location not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Duplicate uri rows.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Resolve a coordinate

- **Method:** `GET`
- **Path:** `/v1/points/resolve`
- **Tags:** points

Resolve WGS84 coordinates to administrative context: anchor, hierarchy, and zones at the point.

Optional `include=postcodes` adds `anchor.postcode` — the Eurostat code at the input coordinates (same lookup as `GET /v1/postcodes/by-point`), or `null` when none matches — and embeds Eurostat codes linked to the anchor location and its subdivisions on `anchor.postcodes`.

Credits per request:

- **2** base
- **5** with `include=polylines`

#### Parameters

##### `lat` required

- **In:** `query`

`string`

##### `lng` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `layers`

- **In:** `query`

**Array of:**

`string`, possible values: `"locations", "zones"`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines", "postcodes"`

#### Responses

##### Status: 200 Point resolve result.

###### Content-Type: application/json

- **`anchor` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

  - **`postcode`**

    `string | null`

  - **`postcodes`**

    `array`

    **Items:**

    `string`

- **`contains` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`country` (required)**

  `string`

- **`hierarchy` (required)**

  `object`

- **`point` (required)**

  `array`

**Example:**

```json
{
  "point": [],
  "country": "",
  "anchor": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "postcodes": [
      ""
    ],
    "postcode": null
  },
  "hierarchy": {
    "additionalProperty": {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ]
    }
  },
  "contains": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ]
    }
  ]
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 No matching layers at the point.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Unified autocomplete

- **Method:** `GET`
- **Path:** `/v1/autocomplete`
- **Tags:** autocomplete

Search-as-you-type across registry layers - locations, postcodes, and zones. Pass `layers` to scope results.

Example: `GET /v1/autocomplete?layers=locations&q=lisboa`

#### Parameters

##### `q` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `layers`

- **In:** `query`

**Array of:**

`string`, possible values: `"locations", "postcodes", "zones"`

##### `limit`

- **In:** `query`

`integer`, default: `5`

##### `lat`

- **In:** `query`

`[ "number", "null" ]`

##### `lng`

- **In:** `query`

`[ "number", "null" ]`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

##### `kinds`

- **In:** `query`

Comma-separated list of location kinds to include. Defaults to all kinds.

`string` — Comma-separated list of location kinds to include. Defaults to all kinds.

#### Responses

##### Status: 200 Autocomplete suggestions.

###### Content-Type: application/json

- **`query` (required)**

  `string`

- **`results` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`label` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`score` (required)**

    `number`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`is_final`**

    `boolean`

  - **`polylines`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "query": "",
  "results": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "score": 1
    }
  ]
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### List postcodes

- **Method:** `GET`
- **Path:** `/v1/postcodes`
- **Tags:** postcodes

Paginated list of Eurostat postcodes from the registry matview.

Filter by `country`, exact `code`, parent LAU `gisco_id`, linked `location_id` (canonical `mb_loc_*`), or free-text `q` on the normalized code. Keyset pagination uses `cursor` on `pc_cntr`.

Optional `include`: `centroid`, `bbox`, or `polylines` embed geometry on each row.

Examples:

- `GET /v1/postcodes?country=PT&code=1000-001&limit=1`
- `GET /v1/postcodes?country=PT&gisco_id=PT_110665&include=centroid`

#### Parameters

##### `limit`

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `code`

- **In:** `query`

`string`

##### `gisco_id`

- **In:** `query`

`string`

##### `location_id`

- **In:** `query`

`string`

##### `q`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 A page of postcodes.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`code` (required)**

    `string`

  - **`country` (required)**

    `string`

  - **`gisco_id` (required)**

    `string | null`

  - **`id` (required)**

    `string`

  - **`lau_name` (required)**

    `string | null`

  - **`location` (required)**

    `object`

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`location_id` (required)**

    `string | null`

  - **`centroid`**

    `array | null`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "code": "",
      "country": "",
      "gisco_id": null,
      "lau_name": null,
      "centroid": null,
      "location_id": null,
      "location": {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get postcode by coordinates

- **Method:** `GET`
- **Path:** `/v1/postcodes/by-point`
- **Tags:** postcodes

Reverse geocode a WGS84 point to the Eurostat postcode that contains it.

The query builds a PostGIS point and searches `postal_codes` (joined to LAU regions): a hit matches when the postcode polygon contains the point, or when the postcode has no geometry and the linked LAU polygon does.

Optional `country` filters to registry countries (PT, ES, IT, UK, FR); a country mismatch returns 404. Optional `include` embeds `centroid`, `bbox`, or `polylines` on the response.

Examples:

- `GET /v1/postcodes/by-point?lat=38.7223&lng=-9.1393`
- `GET /v1/postcodes/by-point?lat=38.7223&lng=-9.1393&country=PT&include=centroid`

#### Parameters

##### `lat` required

- **In:** `query`

`string`

##### `lng` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 Postcode containing the point.

###### Content-Type: application/json

- **`code` (required)**

  `string`

- **`country` (required)**

  `string`

- **`gisco_id` (required)**

  `string | null`

- **`id` (required)**

  `string`

- **`lau_name` (required)**

  `string | null`

- **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`location_id` (required)**

  `string | null`

- **`centroid`**

  `array | null`

**Example:**

```json
{
  "id": "mb_cod_UFRfMTEwMC0wNjI",
  "code": "1100-062",
  "country": "PT",
  "gisco_id": "PT_110665",
  "lau_name": "Santa Maria Maior",
  "centroid": [
    -9.138168592,
    38.710022004
  ],
  "location_id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
  "location": {
    "id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
    "layer": "locations",
    "kind": "neighborhood",
    "country": "PT",
    "name": "Baixa, Lisboa",
    "uri": "santa-maria-maior/baixa",
    "parent_id": "0-EU-PT-11-06-065-65",
    "level": 6,
    "is_final": true,
    "centroid": [
      -9.136837163,
      38.708410674
    ],
    "bbox": [
      -9.141969,
      38.705318,
      -9.13082,
      38.713488
    ],
    "has_boundary": true
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 No postcode covers the point.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get postcode

- **Method:** `GET`
- **Path:** `/v1/postcodes/{identifier}`
- **Tags:** postcodes

Fetch one postcode by canonical `mb_cod_*` id or Eurostat `pc_cntr`.

When the postcode is linked to a location, optional `parent=true` and `hierarchy=true` embed that location's immediate parent and depth-keyed ancestor chain (same shape as location detail). Use `include` for geometry on returned nodes.

Optional `include`: `centroid`, `bbox`, or `polylines` embed geometry from the registry matview.

Examples:

- `GET /v1/postcodes/mb_cod_abc123`
- `GET /v1/postcodes/PT-1000-001?country=PT&include=centroid`
- `GET /v1/postcodes/PT-1000-001?parent=true&hierarchy=true`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `country`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

##### `parent`

- **In:** `query`

`[ "boolean", "null" ]`

##### `hierarchy`

- **In:** `query`

`[ "boolean", "null" ]`

#### Responses

##### Status: 200 A single postcode.

###### Content-Type: application/json

- **`code` (required)**

  `string`

- **`country` (required)**

  `string`

- **`gisco_id` (required)**

  `string | null`

- **`id` (required)**

  `string`

- **`lau_name` (required)**

  `string | null`

- **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`location_id` (required)**

  `string | null`

- **`centroid`**

  `array | null`

- **`hierarchy`**

  `object`

- **`parent`**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "id": "mb_cod_UFRfMTEwMC0wNjI",
  "code": "1100-062",
  "country": "PT",
  "gisco_id": "PT_110665",
  "lau_name": "Santa Maria Maior",
  "centroid": [
    -9.138168592,
    38.710022004
  ],
  "location_id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
  "location": {
    "id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
    "layer": "locations",
    "kind": "neighborhood",
    "country": "PT",
    "name": "Baixa, Lisboa",
    "uri": "santa-maria-maior/baixa",
    "parent_id": "0-EU-PT-11-06-065-65",
    "level": 6,
    "is_final": true,
    "centroid": [
      -9.136837163,
      38.708410674
    ],
    "bbox": [
      -9.141969,
      38.705318,
      -9.13082,
      38.713488
    ],
    "has_boundary": true
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Postcode not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### List zones

- **Method:** `GET`
- **Path:** `/v1/zones`
- **Tags:** zones

Lists active zones from the registry. Filter by canonical location id (`mb_loc_*` on `location_id`). Only active zones are indexed in `search_registry`.

#### Parameters

##### `limit`

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `kind`

- **In:** `query`

`string`

##### `location_id`

- **In:** `query`

`string`

##### `q`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 A page of zones.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`location` (required)**

    `object`

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`location_id` (required)**

    `string | null`

  - **`name` (required)**

    `string`

  - **`status` (required)**

    `string`, possible values: `"active", "inactive"`

  - **`uri` (required)**

    `string`

  - **`centroid`**

    `array | null`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "name": "",
      "uri": "",
      "kind": "",
      "country": "",
      "status": "active",
      "location_id": null,
      "location": {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      },
      "centroid": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get zone boundary

- **Method:** `GET`
- **Path:** `/v1/zones/{identifier}/boundary`
- **Tags:** zones

Polygon geometry for a zone. Accepts canonical `mb_zon_*` id or upstream zone id (no URI).

Example: `GET /v1/zones/mb_zon_UFQtWi0xMDAwOQ/boundary?simplify=0.001&srid=4326`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `simplify`

- **In:** `query`

`[ "number", "null" ]`

##### `srid`

- **In:** `query`

`[ "integer", "null" ]`

#### Responses

##### Status: 200 GeoJSON boundary for the zone.

###### Content-Type: application/json

- **`bbox` (required)**

  `array`

- **`geometry` (required)**

  `object`

- **`id` (required)**

  `string`

- **`layer` (required)**

  `string`, possible values: `"locations", "postcodes", "zones"`

- **`srid` (required)**

  `integer`

**Example:**

```json
{
  "id": "",
  "layer": "locations",
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "bbox": [],
  "srid": 1
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 No boundary stored.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get zone

- **Method:** `GET`
- **Path:** `/v1/zones/{identifier}`
- **Tags:** zones

Fetch one zone by canonical `mb_zon_*` id, upstream zone id, or URL-encoded URI.

Examples:

- `GET /v1/zones/mb_zon_UFQtWi0xMDAwOQ`
- `GET /v1/zones/PT-Z-10009`
- `GET /v1/zones/baixa-chiado?country=PT`

#### Parameters

##### `identifier` required

- **In:** `path`

`string`

##### `country`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

**Array of:**

`string`, possible values: `"centroid", "bbox", "polylines"`

#### Responses

##### Status: 200 A single zone.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`has_boundary` (required)**

  `boolean`

- **`id` (required)**

  `string`

- **`kind` (required)**

  `string`

- **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`location_id` (required)**

  `string | null`

- **`name` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"active", "inactive"`

- **`uri` (required)**

  `string`

- **`centroid`**

  `array | null`

- **`polylines`**

  `array`

  **Items:**

  `string`

**Example:**

```json
{
  "id": "",
  "name": "",
  "uri": "",
  "kind": "",
  "country": "",
  "status": "active",
  "location_id": null,
  "location": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "centroid": null,
  "polylines": [
    ""
  ],
  "has_boundary": true
}
```

##### Status: 400 Ambiguous URI without country.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Zone not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Duplicate uri rows.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Create a zone submission draft

- **Method:** `POST`
- **Path:** `/v1/zone-submissions`
- **Tags:** zone-submissions

Creates a draft zone submission for admin review. Does not publish to the zones registry.

#### Request Body

##### Content-Type: application/json

- **`country` (required)**

  `string`

- **`geometry` (required)**

  `object`

- **`name` (required)**

  `string`

- **`uri` (required)**

  `string`

- **`kind`**

  `string`, default: `"custom_zone"`

- **`notes`**

  `string`

**Example:**

```json
{
  "name": "Test zone",
  "uri": "test-zone",
  "kind": "neighborhood",
  "country": "PT",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          -9.148168592,
          38.700022004000004
        ],
        [
          -9.128168592,
          38.700022004000004
        ],
        [
          -9.128168592,
          38.720022004
        ],
        [
          -9.148168592,
          38.720022004
        ],
        [
          -9.148168592,
          38.700022004000004
        ]
      ]
    ]
  },
  "notes": "Example submission"
}
```

#### Responses

##### Status: 201 Draft submission created.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`created_by` (required)**

  `string`

- **`id` (required)**

  `string`, format: `uuid`

- **`kind` (required)**

  `string`

- **`location_id` (required)**

  `string | null`

- **`name` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"draft", "submitted", "approved", "rejected"`

- **`tenant_id` (required)**

  `string`

- **`updated_at` (required)**

  `string`, format: `date-time`

- **`uri` (required)**

  `string | null`

- **`zone_id` (required)**

  `string | null`

- **`approved_at`**

  `string | null`, format: `date-time`

- **`centroid`**

  `object`

  - **`lat` (required)**

    `number`

  - **`lng` (required)**

    `number`

- **`geometry`**

  `object`

- **`notes`**

  `string | null`

- **`polylines`**

  `array`

  **Items:**

  `string`

- **`rejected_at`**

  `string | null`, format: `date-time`

- **`rejection_reason`**

  `string | null`

- **`submitted_at`**

  `string | null`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "zone_id": null,
  "tenant_id": "",
  "created_by": "",
  "status": "draft",
  "name": "",
  "uri": null,
  "kind": "",
  "country": "",
  "location_id": null,
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "centroid": {
    "lng": 1,
    "lat": 1
  },
  "polylines": [
    ""
  ],
  "notes": null,
  "rejection_reason": null,
  "submitted_at": null,
  "approved_at": null,
  "rejected_at": null,
  "created_at": "",
  "updated_at": ""
}
```

##### Status: 400 Invalid request body.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 409 URI conflict.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Internal error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### List zone submissions

- **Method:** `GET`
- **Path:** `/v1/zone-submissions`
- **Tags:** zone-submissions

Lists zone submissions owned by the authenticated user.

#### Parameters

##### `limit`

- **In:** `query`

`integer`, default: `50`

##### `offset`

- **In:** `query`

`[ "integer", "null" ]`, default: `0`

##### `status`

- **In:** `query`

`string`, possible values: `"draft", "submitted", "approved", "rejected"`

#### Responses

##### Status: 200 A page of submissions.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`created_at` (required)**

    `string`, format: `date-time`

  - **`created_by` (required)**

    `string`

  - **`id` (required)**

    `string`, format: `uuid`

  - **`kind` (required)**

    `string`

  - **`location_id` (required)**

    `string | null`

  - **`name` (required)**

    `string`

  - **`status` (required)**

    `string`, possible values: `"draft", "submitted", "approved", "rejected"`

  - **`tenant_id` (required)**

    `string`

  - **`updated_at` (required)**

    `string`, format: `date-time`

  - **`uri` (required)**

    `string | null`

  - **`zone_id` (required)**

    `string | null`

  - **`approved_at`**

    `string | null`, format: `date-time`

  - **`centroid`**

    `object`

    - **`lat` (required)**

      `number`

    - **`lng` (required)**

      `number`

  - **`geometry`**

    `object`

  - **`notes`**

    `string | null`

  - **`polylines`**

    `array`

    **Items:**

    `string`

  - **`rejected_at`**

    `string | null`, format: `date-time`

  - **`rejection_reason`**

    `string | null`

  - **`submitted_at`**

    `string | null`, format: `date-time`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `number`

  - **`offset` (required)**

    `number`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "zone_id": null,
      "tenant_id": "",
      "created_by": "",
      "status": "draft",
      "name": "",
      "uri": null,
      "kind": "",
      "country": "",
      "location_id": null,
      "geometry": {
        "type": "Point",
        "coordinates": []
      },
      "centroid": {
        "lng": 1,
        "lat": 1
      },
      "polylines": [
        ""
      ],
      "notes": null,
      "rejection_reason": null,
      "submitted_at": null,
      "approved_at": null,
      "rejected_at": null,
      "created_at": "",
      "updated_at": ""
    }
  ],
  "meta": {
    "limit": 1,
    "offset": 1
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get a zone submission

- **Method:** `GET`
- **Path:** `/v1/zone-submissions/{id}`
- **Tags:** zone-submissions

#### Parameters

##### `id` required

- **In:** `path`

`string`, format: `uuid`

#### Responses

##### Status: 200 Submission details.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`created_by` (required)**

  `string`

- **`id` (required)**

  `string`, format: `uuid`

- **`kind` (required)**

  `string`

- **`location_id` (required)**

  `string | null`

- **`name` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"draft", "submitted", "approved", "rejected"`

- **`tenant_id` (required)**

  `string`

- **`updated_at` (required)**

  `string`, format: `date-time`

- **`uri` (required)**

  `string | null`

- **`zone_id` (required)**

  `string | null`

- **`approved_at`**

  `string | null`, format: `date-time`

- **`centroid`**

  `object`

  - **`lat` (required)**

    `number`

  - **`lng` (required)**

    `number`

- **`geometry`**

  `object`

- **`notes`**

  `string | null`

- **`polylines`**

  `array`

  **Items:**

  `string`

- **`rejected_at`**

  `string | null`, format: `date-time`

- **`rejection_reason`**

  `string | null`

- **`submitted_at`**

  `string | null`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "zone_id": null,
  "tenant_id": "",
  "created_by": "",
  "status": "draft",
  "name": "",
  "uri": null,
  "kind": "",
  "country": "",
  "location_id": null,
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "centroid": {
    "lng": 1,
    "lat": 1
  },
  "polylines": [
    ""
  ],
  "notes": null,
  "rejection_reason": null,
  "submitted_at": null,
  "approved_at": null,
  "rejected_at": null,
  "created_at": "",
  "updated_at": ""
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Submission not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Update a zone submission

- **Method:** `PATCH`
- **Path:** `/v1/zone-submissions/{id}`
- **Tags:** zone-submissions

Updates a draft or rejected submission owned by the caller.

#### Parameters

##### `id` required

- **In:** `path`

`string`, format: `uuid`

#### Request Body

##### Content-Type: application/json

- **`country`**

  `string`

- **`geometry`**

  `object`

- **`kind`**

  `string`, default: `"custom_zone"`

- **`name`**

  `string`

- **`notes`**

  `string`

- **`uri`**

  `string`

**Example:**

```json
{
  "name": "Renamed submission",
  "uri": "",
  "kind": "custom_zone",
  "country": "",
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "notes": "Updated notes"
}
```

#### Responses

##### Status: 200 Updated submission.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`created_by` (required)**

  `string`

- **`id` (required)**

  `string`, format: `uuid`

- **`kind` (required)**

  `string`

- **`location_id` (required)**

  `string | null`

- **`name` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"draft", "submitted", "approved", "rejected"`

- **`tenant_id` (required)**

  `string`

- **`updated_at` (required)**

  `string`, format: `date-time`

- **`uri` (required)**

  `string | null`

- **`zone_id` (required)**

  `string | null`

- **`approved_at`**

  `string | null`, format: `date-time`

- **`centroid`**

  `object`

  - **`lat` (required)**

    `number`

  - **`lng` (required)**

    `number`

- **`geometry`**

  `object`

- **`notes`**

  `string | null`

- **`polylines`**

  `array`

  **Items:**

  `string`

- **`rejected_at`**

  `string | null`, format: `date-time`

- **`rejection_reason`**

  `string | null`

- **`submitted_at`**

  `string | null`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "zone_id": null,
  "tenant_id": "",
  "created_by": "",
  "status": "draft",
  "name": "",
  "uri": null,
  "kind": "",
  "country": "",
  "location_id": null,
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "centroid": {
    "lng": 1,
    "lat": 1
  },
  "polylines": [
    ""
  ],
  "notes": null,
  "rejection_reason": null,
  "submitted_at": null,
  "approved_at": null,
  "rejected_at": null,
  "created_at": "",
  "updated_at": ""
}
```

##### Status: 400 Invalid request.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Submission not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 409 Conflict (not editable or URI taken).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Internal error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Delete a zone submission

- **Method:** `DELETE`
- **Path:** `/v1/zone-submissions/{id}`
- **Tags:** zone-submissions

Deletes a draft or rejected submission owned by the caller.

#### Parameters

##### `id` required

- **In:** `path`

`string`, format: `uuid`

#### Responses

##### Status: 200 Submission deleted.

###### Content-Type: application/json

- **`id` (required)**

  `string`, format: `uuid`

**Example:**

```json
{
  "id": ""
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Submission cannot be deleted.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Submission not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Submit a zone submission for review

- **Method:** `POST`
- **Path:** `/v1/zone-submissions/{id}/submit`
- **Tags:** zone-submissions

Transitions a draft or rejected submission to submitted status for admin review.

#### Parameters

##### `id` required

- **In:** `path`

`string`, format: `uuid`

#### Responses

##### Status: 200 Submitted submission.

###### Content-Type: application/json

- **`country` (required)**

  `string`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`created_by` (required)**

  `string`

- **`id` (required)**

  `string`, format: `uuid`

- **`kind` (required)**

  `string`

- **`location_id` (required)**

  `string | null`

- **`name` (required)**

  `string`

- **`status` (required)**

  `string`, possible values: `"draft", "submitted", "approved", "rejected"`

- **`tenant_id` (required)**

  `string`

- **`updated_at` (required)**

  `string`, format: `date-time`

- **`uri` (required)**

  `string | null`

- **`zone_id` (required)**

  `string | null`

- **`approved_at`**

  `string | null`, format: `date-time`

- **`centroid`**

  `object`

  - **`lat` (required)**

    `number`

  - **`lng` (required)**

    `number`

- **`geometry`**

  `object`

- **`notes`**

  `string | null`

- **`polylines`**

  `array`

  **Items:**

  `string`

- **`rejected_at`**

  `string | null`, format: `date-time`

- **`rejection_reason`**

  `string | null`

- **`submitted_at`**

  `string | null`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "zone_id": null,
  "tenant_id": "",
  "created_by": "",
  "status": "draft",
  "name": "",
  "uri": null,
  "kind": "",
  "country": "",
  "location_id": null,
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "centroid": {
    "lng": 1,
    "lat": 1
  },
  "polylines": [
    ""
  ],
  "notes": null,
  "rejection_reason": null,
  "submitted_at": null,
  "approved_at": null,
  "rejected_at": null,
  "created_at": "",
  "updated_at": ""
}
```

##### Status: 400 Invalid submission state.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Submission not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 409 Conflict.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Internal error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Get boundaries

- **Method:** `GET`
- **Path:** `/v1/boundaries`
- **Tags:** boundaries

Bulk boundary fetch with spatial and registry filters. Default output is encoded polylines (`format=polyline`); GeoJSON is capped aggressively.

`country` defaults to `PT`. Requires at least one narrowing filter: `identifier`, `country`, `bbox`, `near`, or `parent_id`.

For a single known entity, use the layer route: `/v1/locations/{identifier}/boundary`, `/v1/zones/{identifier}/boundary`, or `/v1/lau/{identifier}/boundary`.

Examples:

- `GET /v1/boundaries?layer=locations&country=PT&level=4`
- `GET /v1/boundaries?layer=zones&bbox=-9.2,38.7,-9.0,38.8&format=polyline`
- `GET /v1/boundaries?identifier=mb_loc_a,mb_zon_b,mb_lau_c`

#### Parameters

##### `limit` required

- **In:** `query`

`integer`, default: `25`

##### `cursor`

- **In:** `query`

`string`

##### `layer` required

- **In:** `query`
- **Style:** `form`
- **Explode:** `true`

**Array of:**

`string`, possible values: `"locations", "zones"`

- Min items: `1`

##### `identifier`

- **In:** `query`

**Array of:**

`string`

- Min items: `1`

##### `country` required

- **In:** `query`

`string`, possible values: `"PT", "ES", "IT", "UK", "FR"`, default: `"PT"`

##### `kind`

- **In:** `query`

**Array of:**

`string`, possible values: `"arrondissement", "autonomous_city", "autonomous_region", "comarca", "continent", "country", "country_division", "county", "department", "district", "external_region", "island", "municipality", "microstate", "neighborhood", "overseas_department", "parish", "province", "region", "town", "ward", "beach", "zone"`

- Min items: `1`

##### `level`

- **In:** `query`
- **Style:** `form`
- **Explode:** `true`

**Array of:**

`integer`, possible values: `0, 1, 2, 3, 4, 5, 6, 7`

- Min items: `1`

##### `bbox`

- **In:** `query`

`string`

##### `near`

- **In:** `query`

`string`

##### `radius_m`

- **In:** `query`

`integer`

##### `parent_id`

- **In:** `query`

`string`

##### `format` required

- **In:** `query`

`string`, possible values: `"geojson", "polyline"`, default: `"polyline"`

##### `simplify`

- **In:** `query`

`[ "number", "null" ]`

##### `srid`

- **In:** `query`

`[ "integer", "null" ]`

#### Responses

##### Status: 200 A page of boundary items.

###### Content-Type: application/json

- **`data` (required)**

  `array`

  **Items:**

  - **`bbox` (required)**

    `array`

  - **`format` (required)**

    `string`, possible values: `"geojson", "polyline"`

  - **`id` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "zones"`

  - **`srid` (required)**

    `integer`

  - **`country`**

    `string`

  - **`geometry`**

    `object`

  - **`is_final`**

    `boolean`

  - **`kind`**

    `string`

  - **`level`**

    `integer | null`

  - **`name`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "layer": "locations",
      "name": "",
      "kind": "",
      "country": "",
      "level": null,
      "bbox": [],
      "srid": 1,
      "format": "geojson",
      "geometry": {
        "type": "Point",
        "coordinates": []
      },
      "polylines": [
        ""
      ],
      "is_final": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

##### Status: 400 Invalid or ambiguous query.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Referenced location not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 422 Result set too large (GeoJSON).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Full page SEO

- **Method:** `GET`
- **Path:** `/v1/seo/page`
- **Tags:** seo

Returns entity context, breadcrumbs, meta tags, JSON-LD, and optional internal-link sections for a registry entity or coordinate. Resolve by `identifier`, `uri`+`country`, or `lng`+`lat` (exactly one mode). With `uri`+`country`, matches locations and zones by crawl uri, and postcodes by URL slug (e.g. `1000-001`, `SW1A-1AA`). Postcode `identifier` accepts `mb_cod_*`, Eurostat `pc_cntr`, or bare code with `country`.

#### Parameters

##### `include_country_prefix`

- **In:** `query`

`[ "boolean", "null" ]`, default: `true`

##### `from_level`

- **In:** `query`

`number`

##### `filter_level`

- **In:** `query`

`number`, default: `0`

##### `include_intermediate_regions`

- **In:** `query`

`[ "boolean", "null" ]`, default: `false`

##### `identifier`

- **In:** `query`

`string`, default: `"mb_loc_MC1FVS1QVC0xMS0wNg"`

##### `uri`

- **In:** `query`

`string`

##### `lng`

- **In:** `query`

`number`

##### `lat`

- **In:** `query`

`number`

##### `country`

- **In:** `query`

`string`, possible values: `"PT", "ES", "IT", "UK", "FR"`, default: `"PT"`

##### `base_url`

- **In:** `query`

`string`, format: `uri`

##### `site_name`

- **In:** `query`

`string`

##### `locale`

- **In:** `query`

`string`

##### `template`

- **In:** `query`

`string`

##### `include`

- **In:** `query`

`string`

#### Responses

##### Status: 200 SEO page bundle.

###### Content-Type: application/json

- **`breadcrumbs` (required)**

  `array`

  **Items:**

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string`

  - **`uri` (required)**

    `string`

- **`entity` (required)**

  `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

- **`json_ld` (required)**

  `object`

- **`meta` (required)**

  `object`

  - **`canonical_path` (required)**

    `string`

  - **`canonical_url` (required)**

    `string | null`, format: `uri`

  - **`description` (required)**

    `string`

  - **`og_description` (required)**

    `string`

  - **`og_title` (required)**

    `string`

  - **`title` (required)**

    `string`

- **`sections`**

  `array`

  **Items:**

  - **`items` (required)**

    `array`

    **Items:**

    - **`id` (required)**

      `string`

    - **`layer` (required)**

      `string`

    - **`name` (required)**

      `string`

    - **`href`**

      `string | null`, format: `uri`

    - **`path`**

      `string`

    - **`uri`**

      `string | null`

  - **`key` (required)**

    `string`

  - **`title` (required)**

    `string`

**Example:**

```json
{
  "entity": {
    "id": "",
    "layer": "locations",
    "name": "",
    "uri": null,
    "country": "PT",
    "kind": null,
    "level": 0,
    "path": null,
    "href": null
  },
  "breadcrumbs": [
    {
      "name": "",
      "uri": "",
      "layer": "",
      "kind": null,
      "level": 0,
      "path": "",
      "href": null
    }
  ],
  "meta": {
    "title": "",
    "description": "",
    "canonical_path": "",
    "canonical_url": null,
    "og_title": "",
    "og_description": ""
  },
  "json_ld": {},
  "sections": [
    {
      "key": "",
      "title": "",
      "items": [
        {
          "id": "",
          "layer": "",
          "name": "",
          "uri": null,
          "path": "",
          "href": null
        }
      ]
    }
  ]
}
```

##### Status: 400 Invalid or ambiguous request.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Entity not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Duplicate uri rows.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### SEO directory tree nodes

- **Method:** `GET`
- **Path:** `/v1/seo/tree`
- **Tags:** seo

Returns paginated child nodes and internal-link sections for SEO navigation.

#### Parameters

##### `country` required

- **In:** `query`

`string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

##### `layer`

- **In:** `query`

`string`, possible values: `"locations", "postcodes", "zones"`

##### `parent_id`

- **In:** `query`

`string`

##### `identifier`

- **In:** `query`

`string`

##### `uri`

- **In:** `query`

`string`

##### `limit`

- **In:** `query`

`integer`, default: `50`

##### `cursor`

- **In:** `query`

`string`

#### Responses

##### Status: 200 SEO directory tree sections.

###### Content-Type: application/json

- **`breadcrumbs` (required)**

  `array`

  **Items:**

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string`

  - **`uri` (required)**

    `string`

- **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

- **`parent` (required)**

  `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`id` (required)**

    `string`

  - **`layer` (required)**

    `string`

  - **`name` (required)**

    `string`

  - **`kind`**

    `string | null`

  - **`level`**

    `number`

  - **`path`**

    `string`

  - **`source_id`**

    `string`

  - **`uri`**

    `string | null`

- **`sections` (required)**

  `array`

  **Items:**

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

  - **`nodes` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

    - **`id` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`name` (required)**

      `string`

    - **`centroid`**

      `array | null`

    - **`child_count`**

      `integer`

    - **`has_children`**

      `boolean`

    - **`kind`**

      `string | null`

    - **`label`**

      `string`

    - **`level`**

      `number`

    - **`parent_id`**

      `string | null`

    - **`path`**

      `string`

    - **`source_id`**

      `string`

    - **`uri`**

      `string | null`

  - **`title` (required)**

    `string`

**Example:**

```json
{
  "country": "PT",
  "parent": {
    "id": "",
    "source_id": "",
    "layer": "",
    "country": "PT",
    "name": "",
    "kind": null,
    "uri": null,
    "path": "",
    "level": 0
  },
  "breadcrumbs": [
    {
      "name": "",
      "uri": "",
      "layer": "",
      "kind": null,
      "level": 0,
      "path": "",
      "href": null
    }
  ],
  "sections": [
    {
      "layer": "locations",
      "title": "",
      "nodes": [
        {
          "id": "",
          "source_id": "",
          "layer": "locations",
          "country": "PT",
          "name": "",
          "label": "",
          "centroid": null,
          "kind": null,
          "uri": null,
          "path": "",
          "parent_id": null,
          "level": 0,
          "has_children": true,
          "child_count": 0
        }
      ],
      "meta": {
        "limit": 1,
        "next_cursor": null
      }
    }
  ]
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 404 Parent entity not found.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Sitemap

- **Method:** `GET`
- **Path:** `/v1/seo/sitemap`
- **Tags:** seo

Use `mode=shards` for the sitemap index manifest, or `shard=pt-locations-0` for up to 10k canonical URLs in one shard. Optional `base_url` adds absolute `loc` on shard entries.

#### Parameters

##### `mode`

- **In:** `query`

`string`, possible values: `"shards"`

##### `shard`

- **In:** `query`

`string`

##### `base_url`

- **In:** `query`

`string`, format: `uri`

#### Responses

##### Status: 200 Sitemap shard manifest or shard entries.

###### Content-Type: application/json

- **`entries`**

  `array`

  **Items:**

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`lastmod` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`uri` (required)**

    `string`

  - **`kind`**

    `string | null`

  - **`loc`**

    `string`, format: `uri`

- **`meta`**

  `object`

  - **`count` (required)**

    `integer`

  - **`shard` (required)**

    `string`

- **`shards`**

  `array`

  **Items:**

  - **`lastmod` (required)**

    `string | null`

  - **`slug` (required)**

    `string`

**Example:**

```json
{
  "shards": [
    {
      "slug": "",
      "lastmod": null
    }
  ],
  "entries": [
    {
      "uri": "",
      "loc": "",
      "country": "PT",
      "layer": "locations",
      "kind": null,
      "lastmod": null
    }
  ],
  "meta": {
    "shard": "",
    "count": 0
  }
}
```

##### Status: 400 Invalid query parameters.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Google Places autocomplete

- **Method:** `GET`
- **Path:** `/v1/providers/google/autocomplete`
- **Tags:** providers

#### Parameters

##### `q` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

**Array of:**

`string`

- Max items: `5`

##### `lat`

- **In:** `query`

`[ "string", "null" ]`

##### `lng`

- **In:** `query`

`[ "string", "null" ]`

##### `limit`

- **In:** `query`

`integer`, default: `5`

##### `language`

- **In:** `query`

`string`

##### `types`

- **In:** `query`

`string`, default: `"geocode"`

##### `radius`

- **In:** `query`

`integer`

##### `strictbounds`

- **In:** `query`

`[ "boolean", "null" ]`

##### `sessiontoken`

- **In:** `query`

`string`

##### `region`

- **In:** `query`

`string`

#### Responses

##### Status: 200 Raw upstream Google autocomplete JSON.

###### Content-Type: application/json

**Example:**

```json
null
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Google Place details

- **Method:** `GET`
- **Path:** `/v1/providers/google/place`
- **Tags:** providers

#### Parameters

##### `place_id` required

- **In:** `query`

`string`

##### `language`

- **In:** `query`

`string`

##### `region`

- **In:** `query`

`string`

#### Responses

##### Status: 200 Raw upstream Google geocode JSON for a place\_id.

###### Content-Type: application/json

**Example:**

```json
null
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Google geocode

- **Method:** `GET`
- **Path:** `/v1/providers/google/geocode`
- **Tags:** providers

#### Parameters

##### `address` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

**Array of:**

`string`

- Max items: `5`

##### `language`

- **In:** `query`

`string`

##### `region`

- **In:** `query`

`string`

##### `bounds`

- **In:** `query`

`string`

#### Responses

##### Status: 200 Raw upstream Google geocode JSON.

###### Content-Type: application/json

**Example:**

```json
null
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Google reverse geocode

- **Method:** `GET`
- **Path:** `/v1/providers/google/reverse-geocode`
- **Tags:** providers

#### Parameters

##### `lat` required

- **In:** `query`

`string`

##### `lng` required

- **In:** `query`

`string`

##### `language`

- **In:** `query`

`string`

##### `region`

- **In:** `query`

`string`

##### `result_type`

- **In:** `query`

`string`

##### `location_type`

- **In:** `query`

`string`, possible values: `"ROOFTOP", "RANGE_INTERPOLATED", "GEOMETRIC_CENTER", "APPROXIMATE"`

#### Responses

##### Status: 200 Raw upstream Google reverse geocode JSON.

###### Content-Type: application/json

**Example:**

```json
null
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Geoapify place autocomplete

- **Method:** `GET`
- **Path:** `/v1/providers/geoapify/autocomplete`
- **Tags:** providers

#### Parameters

##### `q` required

- **In:** `query`

`string`

##### `country`

- **In:** `query`

`string`

##### `limit`

- **In:** `query`

`integer`, default: `5`

##### `type`

- **In:** `query`

`string`, possible values: `"country", "state", "city", "postcode", "street", "amenity", "locality"`

##### `lang`

- **In:** `query`

`string`

##### `filter`

- **In:** `query`

`string`

##### `bias`

- **In:** `query`

`string`

##### `format`

- **In:** `query`

`string`, possible values: `"json", "xml", "geojson"`, default: `"json"`

#### Responses

##### Status: 200 Autocomplete results.

###### Content-Type: application/json

- **`results` (required)**

  `array`

  **Items:**

  - **`formatted` (required)**

    `string`

  - **`place_id` (required)**

    `string`

  - **`country_code`**

    `string`

  - **`name`**

    `string`

**Example:**

```json
{
  "results": [
    {
      "place_id": "",
      "formatted": "",
      "country_code": "",
      "name": ""
    }
  ]
}
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### Geoapify boundary polygons

- **Method:** `GET`
- **Path:** `/v1/providers/geoapify/boundaries`
- **Tags:** providers

#### Parameters

##### `place_id`

- **In:** `query`

`string`

##### `lat`

- **In:** `query`

`[ "string", "null" ]`

##### `lon`

- **In:** `query`

`[ "string", "null" ]`

##### `geometry`

- **In:** `query`

`string`, possible values: `"point", "geometry_1000", "geometry_5000", "geometry_10000"`, default: `"geometry_1000"`

##### `boundaries`

- **In:** `query`

`string`, possible values: `"administrative", "postal_code", "political", "low_emission_zone"`

##### `lang`

- **In:** `query`

`string`

#### Responses

##### Status: 200 GeoJSON FeatureCollection from Geoapify.

###### Content-Type: application/json

**Example:**

```json
null
```

##### Status: 400 Missing provider API key.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 401 Missing or invalid API key (\`auth\_missing\_key\` / \`auth\_invalid\_key\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 402 Credits exhausted or payment blocked (\`payment\_required\`). Update billing to continue.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 403 Request origin or IP is not allowed (\`domain\_forbidden\` / \`ip\_forbidden\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 429 Rate limit or quota exceeded (\`rate\_limited\` / \`daily\_quota\_exceeded\` / \`monthly\_quota\_exceeded\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 500 Unexpected server error (\`internal\_error\`).

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 502 Upstream provider error.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

##### Status: 503 A data dependency is temporarily unavailable (\`service\_unavailable\`). Retry shortly.

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

## Schemas

### CountryCode

- **Type:**`string`

ISO 3166-1 alpha-2 country code. PT, ES, IT, UK, or FR on location and address surfaces.

**Example:**

### FilterKinds

- **Type:**`string`

Comma-separated list of location kinds to include. Defaults to all kinds.

**Example:**

### FilterLevels

- **Type:**`string`

Comma-separated admin depths to include (1=country … 7=block).

**Example:**

### FilterParentId

- **Type:**`string`

Filter by parent location id. Pass the literal string `null` to fetch root rows.

**Example:**

### FilterBbox

- **Type:**`string`

Bounding box as `minLng,minLat,maxLng,maxLat`. Filters via PostGIS ST\_Intersects.

**Example:**

### FilterNear

- **Type:**`string`

Optional `lng,lat` bias or centre point.

**Example:**

### FilterRadiusM

- **Type:**`integer`

Radius in metres around `near`. Default 5000 when `near` is set without an explicit radius.

**Example:**

### FilterLang

- **Type:**`string`

Selects between native name and translated columns (`name_engl`, `name_fren`, `name_germ`).

**Example:**

### FilterLimit

- **Type:**`integer`

Max items per page.

**Example:**

### FilterBoundaryLimit

- **Type:**`integer`

Max items per page for bulk boundary scans (`format=polyline` default).

**Example:**

### FilterOffset

- **Type:**`integer`

Offset pagination. Mutually exclusive with `cursor`.

**Example:**

### FilterCursor

- **Type:**`string`

Opaque pagination cursor returned by a previous response.

**Example:**

### FilterSrid

- **Type:**`integer`

Output coordinate reference (EPSG). Default 4326 (WGS84).

**Example:**

### CountryQueryParam

- **Type:**`object`

* **`country`**

  `string` — ISO 3166-1 alpha-2 country code. PT, ES, IT, UK, or FR on location and address surfaces.

**Example:**

```json
{
  "country": "PT"
}
```

### KindsQueryParam

- **Type:**`object`

* **`kinds`**

  `string` — Comma-separated list of location kinds to include. Defaults to all kinds.

**Example:**

```json
{
  "kinds": "town,district"
}
```

### LevelsQueryParam

- **Type:**`object`

* **`levels`**

  `string` — Comma-separated admin depths to include (1=country … 7=block).

**Example:**

```json
{
  "levels": "4,5"
}
```

### ParentQueryParam

- **Type:**`object`

* **`parent_id`**

  `string` — Filter by parent location id. Pass the literal string \`null\` to fetch root rows.

**Example:**

```json
{
  "parent_id": "pt"
}
```

### BboxQueryParam

- **Type:**`object`

* **`bbox`**

  `string` — Bounding box as \`minLng,minLat,maxLng,maxLat\`. Filters via PostGIS ST\_Intersects.

**Example:**

```json
{
  "bbox": "-9.2,38.7,-9.0,38.8"
}
```

### NearQueryParam

- **Type:**`object`

* **`near`**

  `string` — Optional \`lng,lat\` bias or centre point.

**Example:**

```json
{
  "near": "-9.1393,38.7223"
}
```

### RadiusQueryParam

- **Type:**`object`

* **`radius_m`**

  `integer` — Radius in metres around \`near\`. Default 5000 when \`near\` is set without an explicit radius.

**Example:**

```json
{
  "radius_m": 5000
}
```

### LangQueryParam

- **Type:**`object`

* **`lang`**

  `string`, possible values: `"native", "en", "fr", "de"` — Selects between native name and translated columns (\`name\_engl\`, \`name\_fren\`, \`name\_germ\`).

**Example:**

```json
{
  "lang": "en"
}
```

### PaginationQueryParam

- **Type:**`object`

* **`cursor`**

  `string` — Opaque pagination cursor returned by a previous response.

* **`limit`**

  `integer` — Max items per page.

* **`offset`**

  `integer` — Offset pagination. Mutually exclusive with \`cursor\`.

**Example:**

```json
{
  "limit": 50,
  "offset": 0,
  "cursor": ""
}
```

### BoundaryPaginationQueryParam

- **Type:**`object`

* **`cursor`**

  `string` — Opaque pagination cursor returned by a previous response.

* **`limit`**

  `integer` — Max items per page for bulk boundary scans (\`format=polyline\` default).

**Example:**

```json
{
  "limit": 50,
  "cursor": ""
}
```

### SridQueryParam

- **Type:**`object`

* **`srid`**

  `integer`, possible values: `4326, 3857, 25829, 32629` — Output coordinate reference (EPSG). Default 4326 (WGS84).

**Example:**

```json
{
  "srid": 4326
}
```

### HealthResponse

- **Type:**`object`

* **`environment` (required)**

  `string`

* **`status` (required)**

  `string`, possible values: `"ok"`

* **`uptime_ms` (required)**

  `integer`

* **`version` (required)**

  `string`

**Example:**

```json
{
  "status": "ok",
  "uptime_ms": 1,
  "version": "",
  "environment": ""
}
```

### RedisHealthResponse

- **Type:**

**Example:**

### LayersResponse

- **Type:**`object`

* **`layers` (required)**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`label` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`countries`**

    `array`

    **Items:**

    `string`

* **`breakdown`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level`**

    `number`

* **`byLayerCountry`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

* **`countries`**

  `array`

  **Items:**

  - **`count` (required)**

    `integer`

  - **`country` (required)**

    `string`

**Example:**

```json
{
  "layers": [
    {
      "layer": "locations",
      "label": "",
      "count": 0,
      "countries": [
        ""
      ]
    }
  ],
  "countries": [
    {
      "country": "",
      "count": 0
    }
  ],
  "byLayerCountry": [
    {
      "layer": "locations",
      "country": "",
      "count": 0
    }
  ],
  "breakdown": [
    {
      "layer": "locations",
      "country": "",
      "kind": null,
      "level": 0,
      "count": 0
    }
  ]
}
```

### LocationListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

### ApiErrorEnvelope

- **Type:**`object`

* **`error` (required)**

  `object`

  - **`code` (required)**

    `string`

  - **`message` (required)**

    `string`

  - **`request_id` (required)**

    `string`

  - **`detail`**

    `string`

  - **`scope`**

    `string`

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "scope": "",
    "detail": "",
    "request_id": ""
  }
}
```

### LocationRelationsResponse

- **Type:**`object`

* **`ancestors` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`children` (required)**

  `object`

  - **`data` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

* **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`parent` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`siblings` (required)**

  `object`

  - **`data` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

**Example:**

```json
{
  "location": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "parent": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "children": {
    "data": [
      {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    ],
    "meta": {
      "limit": 1,
      "next_cursor": null
    }
  },
  "siblings": {
    "data": [
      {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    ],
    "meta": {
      "limit": 1,
      "next_cursor": null
    }
  },
  "ancestors": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ]
}
```

### BoundaryResponse

- **Type:**`object`

* **`bbox` (required)**

  `array`

* **`geometry` (required)**

  `object`

* **`id` (required)**

  `string`

* **`layer` (required)**

  `string`, possible values: `"locations", "postcodes", "zones"`

* **`srid` (required)**

  `integer`

**Example:**

```json
{
  "id": "",
  "layer": "locations",
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "bbox": [],
  "srid": 1
}
```

### ZoneListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`location` (required)**

    `object`

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`location_id` (required)**

    `string | null`

  - **`name` (required)**

    `string`

  - **`status` (required)**

    `string`, possible values: `"active", "inactive"`

  - **`uri` (required)**

    `string`

  - **`centroid`**

    `array | null`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "name": "",
      "uri": "",
      "kind": "",
      "country": "",
      "status": "active",
      "location_id": null,
      "location": {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      },
      "centroid": null,
      "polylines": [
        ""
      ],
      "has_boundary": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

### LocationDetail

- **Type:**`object`

* **`country` (required)**

  `string`

* **`has_boundary` (required)**

  `boolean`

* **`id` (required)**

  `string`

* **`is_final` (required)**

  `boolean`

* **`kind` (required)**

  `string`

* **`layer` (required)**

  `string`, possible values: `"locations", "postcodes", "zones"`

* **`level` (required)**

  `number`

* **`name` (required)**

  `string`

* **`parent_id` (required)**

  `string | null`

* **`uri` (required)**

  `string | null`

* **`bbox`**

  `array | null`

* **`centroid`**

  `array | null`

* **`hierarchy`**

  `object`

* **`label`**

  `string`

* **`parent`**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`polylines`**

  `array`

  **Items:**

  `string`

* **`postcodes`**

  `array`

  **Items:**

  `string`

**Example:**

```json
{
  "id": "mb_loc_MC1FVS1QVC0xMS0wNg",
  "layer": "locations",
  "kind": "municipality",
  "country": "PT",
  "name": "Lisboa",
  "uri": "lisboa",
  "parent_id": "mb_loc_MC1FVS1QVC0xMQ",
  "level": 4,
  "is_final": false,
  "has_boundary": true,
  "parent": {
    "id": "mb_loc_MC1FVS1QVC0xMQ",
    "layer": "locations",
    "kind": "district",
    "country": "PT",
    "name": "Lisboa distrito",
    "uri": "lisboa-distrito",
    "parent_id": "mb_loc_MC1FVS1QVC1DT05U",
    "level": 3,
    "is_final": false,
    "has_boundary": true
  },
  "hierarchy": {
    "1": {
      "id": "mb_loc_MC1FVS1QVA",
      "layer": "locations",
      "kind": "country",
      "country": "PT",
      "name": "Portugal",
      "uri": "pt",
      "parent_id": null,
      "level": 1,
      "is_final": false,
      "has_boundary": true
    },
    "2": {
      "id": "mb_loc_MC1FVS1QVC1DT05U",
      "layer": "locations",
      "kind": "continent",
      "country": "PT",
      "name": "Portugal (continente)",
      "uri": "portugal-continent",
      "parent_id": "mb_loc_MC1FVS1QVA",
      "level": 2,
      "is_final": false,
      "has_boundary": true
    },
    "3": {
      "id": "mb_loc_MC1FVS1QVC0xMQ",
      "layer": "locations",
      "kind": "district",
      "country": "PT",
      "name": "Lisboa distrito",
      "uri": "lisboa-distrito",
      "parent_id": "mb_loc_MC1FVS1QVC1DT05U",
      "level": 3,
      "is_final": false,
      "has_boundary": true
    },
    "4": {
      "id": "mb_loc_MC1FVS1QVC0xMS0wNg",
      "layer": "locations",
      "kind": "municipality",
      "country": "PT",
      "name": "Lisboa",
      "uri": "lisboa",
      "parent_id": "mb_loc_MC1FVS1QVC0xMQ",
      "level": 4,
      "is_final": false,
      "has_boundary": true
    }
  }
}
```

### PointResolveResponse

- **Type:**`object`

* **`anchor` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

  - **`postcode`**

    `string | null`

  - **`postcodes`**

    `array`

    **Items:**

    `string`

* **`contains` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`country` (required)**

  `string`

* **`hierarchy` (required)**

  `object`

* **`point` (required)**

  `array`

**Example:**

```json
{
  "point": [],
  "country": "",
  "anchor": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "postcodes": [
      ""
    ],
    "postcode": null
  },
  "hierarchy": {
    "additionalProperty": {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ]
    }
  },
  "contains": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ]
    }
  ]
}
```

### AutocompleteResponse

- **Type:**`object`

* **`query` (required)**

  `string`

* **`results` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`

  - **`label` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`score` (required)**

    `number`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`is_final`**

    `boolean`

  - **`polylines`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "query": "",
  "results": [
    {
      "id": "",
      "layer": "locations",
      "kind": "",
      "country": "",
      "name": "",
      "label": "",
      "uri": null,
      "parent_id": null,
      "level": 0,
      "is_final": true,
      "centroid": null,
      "bbox": null,
      "polylines": [
        ""
      ],
      "score": 1
    }
  ]
}
```

### PostcodeListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`code` (required)**

    `string`

  - **`country` (required)**

    `string`

  - **`gisco_id` (required)**

    `string | null`

  - **`id` (required)**

    `string`

  - **`lau_name` (required)**

    `string | null`

  - **`location` (required)**

    `object`

    - **`country` (required)**

      `string`

    - **`has_boundary` (required)**

      `boolean`

    - **`id` (required)**

      `string`

    - **`is_final` (required)**

      `boolean`

    - **`kind` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`level` (required)**

      `number`

    - **`name` (required)**

      `string`

    - **`parent_id` (required)**

      `string | null`

    - **`uri` (required)**

      `string | null`

    - **`bbox`**

      `array | null`

    - **`centroid`**

      `array | null`

    - **`label`**

      `string`

    - **`polylines`**

      `array`

      **Items:**

      `string`

  - **`location_id` (required)**

    `string | null`

  - **`centroid`**

    `array | null`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "code": "",
      "country": "",
      "gisco_id": null,
      "lau_name": null,
      "centroid": null,
      "location_id": null,
      "location": {
        "id": "",
        "layer": "locations",
        "kind": "",
        "country": "",
        "name": "",
        "label": "",
        "uri": null,
        "parent_id": null,
        "level": 0,
        "is_final": true,
        "centroid": null,
        "bbox": null,
        "polylines": [
          ""
        ],
        "has_boundary": true
      }
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

### Postcode

- **Type:**`object`

* **`code` (required)**

  `string`

* **`country` (required)**

  `string`

* **`gisco_id` (required)**

  `string | null`

* **`id` (required)**

  `string`

* **`lau_name` (required)**

  `string | null`

* **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`location_id` (required)**

  `string | null`

* **`centroid`**

  `array | null`

**Example:**

```json
{
  "id": "mb_cod_UFRfMTEwMC0wNjI",
  "code": "1100-062",
  "country": "PT",
  "gisco_id": "PT_110665",
  "lau_name": "Santa Maria Maior",
  "centroid": [
    -9.138168592,
    38.710022004
  ],
  "location_id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
  "location": {
    "id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
    "layer": "locations",
    "kind": "neighborhood",
    "country": "PT",
    "name": "Baixa, Lisboa",
    "uri": "santa-maria-maior/baixa",
    "parent_id": "0-EU-PT-11-06-065-65",
    "level": 6,
    "is_final": true,
    "centroid": [
      -9.136837163,
      38.708410674
    ],
    "bbox": [
      -9.141969,
      38.705318,
      -9.13082,
      38.713488
    ],
    "has_boundary": true
  }
}
```

### PostcodeDetail

- **Type:**`object`

* **`code` (required)**

  `string`

* **`country` (required)**

  `string`

* **`gisco_id` (required)**

  `string | null`

* **`id` (required)**

  `string`

* **`lau_name` (required)**

  `string | null`

* **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`location_id` (required)**

  `string | null`

* **`centroid`**

  `array | null`

* **`hierarchy`**

  `object`

* **`parent`**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "id": "mb_cod_UFRfMTEwMC0wNjI",
  "code": "1100-062",
  "country": "PT",
  "gisco_id": "PT_110665",
  "lau_name": "Santa Maria Maior",
  "centroid": [
    -9.138168592,
    38.710022004
  ],
  "location_id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
  "location": {
    "id": "mb_loc_MC1FVS1QVC0xMS0wNi0wNjUtNjUtMDI",
    "layer": "locations",
    "kind": "neighborhood",
    "country": "PT",
    "name": "Baixa, Lisboa",
    "uri": "santa-maria-maior/baixa",
    "parent_id": "0-EU-PT-11-06-065-65",
    "level": 6,
    "is_final": true,
    "centroid": [
      -9.136837163,
      38.708410674
    ],
    "bbox": [
      -9.141969,
      38.705318,
      -9.13082,
      38.713488
    ],
    "has_boundary": true
  }
}
```

### Zone

- **Type:**`object`

* **`country` (required)**

  `string`

* **`has_boundary` (required)**

  `boolean`

* **`id` (required)**

  `string`

* **`kind` (required)**

  `string`

* **`location` (required)**

  `object`

  - **`country` (required)**

    `string`

  - **`has_boundary` (required)**

    `boolean`

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean`

  - **`kind` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

  - **`bbox`**

    `array | null`

  - **`centroid`**

    `array | null`

  - **`label`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`location_id` (required)**

  `string | null`

* **`name` (required)**

  `string`

* **`status` (required)**

  `string`, possible values: `"active", "inactive"`

* **`uri` (required)**

  `string`

* **`centroid`**

  `array | null`

* **`polylines`**

  `array`

  **Items:**

  `string`

**Example:**

```json
{
  "id": "",
  "name": "",
  "uri": "",
  "kind": "",
  "country": "",
  "status": "active",
  "location_id": null,
  "location": {
    "id": "",
    "layer": "locations",
    "kind": "",
    "country": "",
    "name": "",
    "label": "",
    "uri": null,
    "parent_id": null,
    "level": 0,
    "is_final": true,
    "centroid": null,
    "bbox": null,
    "polylines": [
      ""
    ],
    "has_boundary": true
  },
  "centroid": null,
  "polylines": [
    ""
  ],
  "has_boundary": true
}
```

### ZoneSubmission

- **Type:**`object`

* **`country` (required)**

  `string`

* **`created_at` (required)**

  `string`, format: `date-time`

* **`created_by` (required)**

  `string`

* **`id` (required)**

  `string`, format: `uuid`

* **`kind` (required)**

  `string`

* **`location_id` (required)**

  `string | null`

* **`name` (required)**

  `string`

* **`status` (required)**

  `string`, possible values: `"draft", "submitted", "approved", "rejected"`

* **`tenant_id` (required)**

  `string`

* **`updated_at` (required)**

  `string`, format: `date-time`

* **`uri` (required)**

  `string | null`

* **`zone_id` (required)**

  `string | null`

* **`approved_at`**

  `string | null`, format: `date-time`

* **`centroid`**

  `object`

  - **`lat` (required)**

    `number`

  - **`lng` (required)**

    `number`

* **`geometry`**

  `object`

* **`notes`**

  `string | null`

* **`polylines`**

  `array`

  **Items:**

  `string`

* **`rejected_at`**

  `string | null`, format: `date-time`

* **`rejection_reason`**

  `string | null`

* **`submitted_at`**

  `string | null`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "zone_id": null,
  "tenant_id": "",
  "created_by": "",
  "status": "draft",
  "name": "",
  "uri": null,
  "kind": "",
  "country": "",
  "location_id": null,
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "centroid": {
    "lng": 1,
    "lat": 1
  },
  "polylines": [
    ""
  ],
  "notes": null,
  "rejection_reason": null,
  "submitted_at": null,
  "approved_at": null,
  "rejected_at": null,
  "created_at": "",
  "updated_at": ""
}
```

### ZoneSubmissionCreate

- **Type:**`object`

* **`country` (required)**

  `string`

* **`geometry` (required)**

  `object`

* **`name` (required)**

  `string`

* **`uri` (required)**

  `string`

* **`kind`**

  `string`, default: `"custom_zone"`

* **`notes`**

  `string`

**Example:**

```json
{
  "name": "Test zone",
  "uri": "test-zone",
  "kind": "neighborhood",
  "country": "PT",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          -9.148168592,
          38.700022004000004
        ],
        [
          -9.128168592,
          38.700022004000004
        ],
        [
          -9.128168592,
          38.720022004
        ],
        [
          -9.148168592,
          38.720022004
        ],
        [
          -9.148168592,
          38.700022004000004
        ]
      ]
    ]
  },
  "notes": "Example submission"
}
```

### ZoneSubmissionListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`country` (required)**

    `string`

  - **`created_at` (required)**

    `string`, format: `date-time`

  - **`created_by` (required)**

    `string`

  - **`id` (required)**

    `string`, format: `uuid`

  - **`kind` (required)**

    `string`

  - **`location_id` (required)**

    `string | null`

  - **`name` (required)**

    `string`

  - **`status` (required)**

    `string`, possible values: `"draft", "submitted", "approved", "rejected"`

  - **`tenant_id` (required)**

    `string`

  - **`updated_at` (required)**

    `string`, format: `date-time`

  - **`uri` (required)**

    `string | null`

  - **`zone_id` (required)**

    `string | null`

  - **`approved_at`**

    `string | null`, format: `date-time`

  - **`centroid`**

    `object`

    - **`lat` (required)**

      `number`

    - **`lng` (required)**

      `number`

  - **`geometry`**

    `object`

  - **`notes`**

    `string | null`

  - **`polylines`**

    `array`

    **Items:**

    `string`

  - **`rejected_at`**

    `string | null`, format: `date-time`

  - **`rejection_reason`**

    `string | null`

  - **`submitted_at`**

    `string | null`, format: `date-time`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `number`

  - **`offset` (required)**

    `number`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "zone_id": null,
      "tenant_id": "",
      "created_by": "",
      "status": "draft",
      "name": "",
      "uri": null,
      "kind": "",
      "country": "",
      "location_id": null,
      "geometry": {
        "type": "Point",
        "coordinates": []
      },
      "centroid": {
        "lng": 1,
        "lat": 1
      },
      "polylines": [
        ""
      ],
      "notes": null,
      "rejection_reason": null,
      "submitted_at": null,
      "approved_at": null,
      "rejected_at": null,
      "created_at": "",
      "updated_at": ""
    }
  ],
  "meta": {
    "limit": 1,
    "offset": 1
  }
}
```

### ZoneSubmissionUpdate

- **Type:**`object`

* **`country`**

  `string`

* **`geometry`**

  `object`

* **`kind`**

  `string`, default: `"custom_zone"`

* **`name`**

  `string`

* **`notes`**

  `string`

* **`uri`**

  `string`

**Example:**

```json
{
  "name": "Renamed submission",
  "uri": "",
  "kind": "custom_zone",
  "country": "",
  "geometry": {
    "type": "Point",
    "coordinates": []
  },
  "notes": "Updated notes"
}
```

### ZoneSubmissionDeleteResponse

- **Type:**`object`

* **`id` (required)**

  `string`, format: `uuid`

**Example:**

```json
{
  "id": ""
}
```

### BoundaryListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`bbox` (required)**

    `array`

  - **`format` (required)**

    `string`, possible values: `"geojson", "polyline"`

  - **`id` (required)**

    `string`

  - **`layer` (required)**

    `string`, possible values: `"locations", "zones"`

  - **`srid` (required)**

    `integer`

  - **`country`**

    `string`

  - **`geometry`**

    `object`

  - **`is_final`**

    `boolean`

  - **`kind`**

    `string`

  - **`level`**

    `integer | null`

  - **`name`**

    `string`

  - **`polylines`**

    `array`

    **Items:**

    `string`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`next_cursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "",
      "layer": "locations",
      "name": "",
      "kind": "",
      "country": "",
      "level": null,
      "bbox": [],
      "srid": 1,
      "format": "geojson",
      "geometry": {
        "type": "Point",
        "coordinates": []
      },
      "polylines": [
        ""
      ],
      "is_final": true
    }
  ],
  "meta": {
    "limit": 1,
    "next_cursor": null
  }
}
```

### SeoPageResponse

- **Type:**`object`

* **`breadcrumbs` (required)**

  `array`

  **Items:**

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string`

  - **`uri` (required)**

    `string`

* **`entity` (required)**

  `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string | null`

  - **`uri` (required)**

    `string | null`

* **`json_ld` (required)**

  `object`

* **`meta` (required)**

  `object`

  - **`canonical_path` (required)**

    `string`

  - **`canonical_url` (required)**

    `string | null`, format: `uri`

  - **`description` (required)**

    `string`

  - **`og_description` (required)**

    `string`

  - **`og_title` (required)**

    `string`

  - **`title` (required)**

    `string`

* **`sections`**

  `array`

  **Items:**

  - **`items` (required)**

    `array`

    **Items:**

    - **`id` (required)**

      `string`

    - **`layer` (required)**

      `string`

    - **`name` (required)**

      `string`

    - **`href`**

      `string | null`, format: `uri`

    - **`path`**

      `string`

    - **`uri`**

      `string | null`

  - **`key` (required)**

    `string`

  - **`title` (required)**

    `string`

**Example:**

```json
{
  "entity": {
    "id": "",
    "layer": "locations",
    "name": "",
    "uri": null,
    "country": "PT",
    "kind": null,
    "level": 0,
    "path": null,
    "href": null
  },
  "breadcrumbs": [
    {
      "name": "",
      "uri": "",
      "layer": "",
      "kind": null,
      "level": 0,
      "path": "",
      "href": null
    }
  ],
  "meta": {
    "title": "",
    "description": "",
    "canonical_path": "",
    "canonical_url": null,
    "og_title": "",
    "og_description": ""
  },
  "json_ld": {},
  "sections": [
    {
      "key": "",
      "title": "",
      "items": [
        {
          "id": "",
          "layer": "",
          "name": "",
          "uri": null,
          "path": "",
          "href": null
        }
      ]
    }
  ]
}
```

### SeoTreeResponse

- **Type:**`object`

* **`breadcrumbs` (required)**

  `array`

  **Items:**

  - **`href` (required)**

    `string | null`, format: `uri`

  - **`kind` (required)**

    `string | null`

  - **`layer` (required)**

    `string`

  - **`level` (required)**

    `number`

  - **`name` (required)**

    `string`

  - **`path` (required)**

    `string`

  - **`uri` (required)**

    `string`

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

* **`parent` (required)**

  `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`id` (required)**

    `string`

  - **`layer` (required)**

    `string`

  - **`name` (required)**

    `string`

  - **`kind`**

    `string | null`

  - **`level`**

    `number`

  - **`path`**

    `string`

  - **`source_id`**

    `string`

  - **`uri`**

    `string | null`

* **`sections` (required)**

  `array`

  **Items:**

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`meta` (required)**

    `object`

    - **`limit` (required)**

      `integer`

    - **`next_cursor` (required)**

      `string | null`

  - **`nodes` (required)**

    `array`

    **Items:**

    - **`country` (required)**

      `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

    - **`id` (required)**

      `string`

    - **`layer` (required)**

      `string`, possible values: `"locations", "postcodes", "zones"`

    - **`name` (required)**

      `string`

    - **`centroid`**

      `array | null`

    - **`child_count`**

      `integer`

    - **`has_children`**

      `boolean`

    - **`kind`**

      `string | null`

    - **`label`**

      `string`

    - **`level`**

      `number`

    - **`parent_id`**

      `string | null`

    - **`path`**

      `string`

    - **`source_id`**

      `string`

    - **`uri`**

      `string | null`

  - **`title` (required)**

    `string`

**Example:**

```json
{
  "country": "PT",
  "parent": {
    "id": "",
    "source_id": "",
    "layer": "",
    "country": "PT",
    "name": "",
    "kind": null,
    "uri": null,
    "path": "",
    "level": 0
  },
  "breadcrumbs": [
    {
      "name": "",
      "uri": "",
      "layer": "",
      "kind": null,
      "level": 0,
      "path": "",
      "href": null
    }
  ],
  "sections": [
    {
      "layer": "locations",
      "title": "",
      "nodes": [
        {
          "id": "",
          "source_id": "",
          "layer": "locations",
          "country": "PT",
          "name": "",
          "label": "",
          "centroid": null,
          "kind": null,
          "uri": null,
          "path": "",
          "parent_id": null,
          "level": 0,
          "has_children": true,
          "child_count": 0
        }
      ],
      "meta": {
        "limit": 1,
        "next_cursor": null
      }
    }
  ]
}
```

### SeoSitemapResponse

- **Type:**`object`

* **`entries`**

  `array`

  **Items:**

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT", "UK", "FR"`

  - **`lastmod` (required)**

    `string | null`

  - **`layer` (required)**

    `string`, possible values: `"locations", "postcodes", "zones"`

  - **`uri` (required)**

    `string`

  - **`kind`**

    `string | null`

  - **`loc`**

    `string`, format: `uri`

* **`meta`**

  `object`

  - **`count` (required)**

    `integer`

  - **`shard` (required)**

    `string`

* **`shards`**

  `array`

  **Items:**

  - **`lastmod` (required)**

    `string | null`

  - **`slug` (required)**

    `string`

**Example:**

```json
{
  "shards": [
    {
      "slug": "",
      "lastmod": null
    }
  ],
  "entries": [
    {
      "uri": "",
      "loc": "",
      "country": "PT",
      "layer": "locations",
      "kind": null,
      "lastmod": null
    }
  ],
  "meta": {
    "shard": "",
    "count": 0
  }
}
```

### GoogleAutocompleteResponse

- **Type:**

**Example:**

### GooglePlaceDetailsResponse

- **Type:**

**Example:**

### GoogleGeocodeResponse

- **Type:**

**Example:**

### GoogleReverseGeocodeResponse

- **Type:**

**Example:**

### GeoapifyAutocompleteResponse

- **Type:**`object`

* **`results` (required)**

  `array`

  **Items:**

  - **`formatted` (required)**

    `string`

  - **`place_id` (required)**

    `string`

  - **`country_code`**

    `string`

  - **`name`**

    `string`

**Example:**

```json
{
  "results": [
    {
      "place_id": "",
      "formatted": "",
      "country_code": "",
      "name": ""
    }
  ]
}
```

### GeoapifyBoundariesResponse

- **Type:**

**Example:**
