# Mapbase Engine API

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

The **Mapbase Engine** is the public HTTP API that powers every Mapbase product surface: the dashboard, the hosted blocks, the SDK, and the docs site you're reading right now.

This reference is generated from the same Zod/OpenAPI contracts that the engine uses at runtime, so the shapes you see here are guaranteed to match the wire format.

## Use it from your app

Two officially-supported integration paths:

- **TypeScript SDK** — `bun add mapbase` ([npm](https://www.npmjs.com/package/mapbase)) exposes a typed client whose response shapes are generated from this exact OpenAPI document via `openapi-typescript`. Resend-style `{ data, error, rateLimit }` returns; one `MapbaseError` class. Quickstart: [mapbase.dev/docs/sdk](https://mapbase.dev/docs/sdk).
- **React components** — copy-paste registry at [mapbase.dev/components](https://mapbase.dev/components) and [mapbase.dev/blocks](https://mapbase.dev/blocks). Install with `bunx shadcn@latest add https://mapbase.dev/r/<name>.json`. Built on shadcn primitives, MapLibre, and the SDK above.

For other languages or build tools, generate a client straight from `/openapi.json` — every shape on this page is ready for codegen.

## Status

The engine is currently in its **boilerplate phase**. Every route under `/v1` is declared with its full request and response contract, but handlers return a typed `501 { error: "not_implemented", endpoint }` envelope until backing logic lands. You can already generate clients, point an LLM at `/openapi.json` for context, or wire up integrations against the stable shapes.

## Base URL & versioning

All stable routes live under `/v1`. Breaking changes ship behind new version prefixes; additive changes land inside `/v1`. The engine also exposes a few unversioned utility routes (`/health`, `/openapi.json`, `/reference`) that are not part of the API contract.

## Authentication

Requests may be authenticated with an API key sent in the `x-api-key` header. The key is **not enforced** during the boilerplate phase — every request is accepted — but clients should start sending the header now so they're ready when enforcement turns on.

## Errors

Every error response follows a single envelope:

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": "This route is part of the public API surface but not wired yet."
}
```

`error` is a short machine-readable slug, `endpoint` identifies the route that produced the error, and `message` is a human-readable description. Additional fields may be added over time.

## Pagination

List endpoints accept `page` and `pageSize` query parameters and return a `meta` object with `page`, `pageSize`, and `total`. Cursor pagination may be added later for large result sets.

## LLM-friendly reference

A Markdown rendering of this document is served at [/llms.txt](/llms.txt) on the docs site. Point an LLM at it to get full context without needing to parse OpenAPI.

## Servers

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

## Operations

### Liveness probe

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

Returns service liveness, uptime, and version metadata.

#### Responses

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

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

- **`environment` (required)**

  `string`

- **`status` (required)**

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

- **`uptimeMs` (required)**

  `integer`

- **`version` (required)**

  `string`

**Example:**

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

### List locations

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

Paginated list of administrative and named locations. Filterable by country, kind, parent, and leaf marker.

#### Responses

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

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

- **`data` (required)**

  `array`

  **Items:**

  - **`centroid` (required)**

    `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`depth` (required)**

    `integer` — Zero-based depth in the country's location tree (country = 0).

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean` — True when this location is a leaf in the crawl tree (no further administrative children).

  - **`kind` (required)**

    `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`nextCursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa",
      "parent_id": "pt",
      "country": null,
      "name": "Lisboa",
      "kind": null,
      "uri": "lisboa",
      "is_final": false,
      "depth": 1,
      "centroid": null
    }
  ],
  "meta": {
    "limit": 1,
    "nextCursor": null
  }
}
```

### Autocomplete locations

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

Trigram-backed, accent- and case-insensitive autocomplete over administrative and named locations. Designed for typeahead UIs: returns a small ranked list of suggestions with breadcrumb labels and similarity scores.

#### Responses

##### Status: 200 A ranked list of suggestions.

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

- **`data` (required)**

  `array`

  **Items:**

  - **`breadcrumb` (required)**

    `string` — Hierarchical label leaf -> root, comma-separated.

  - **`centroid` (required)**

    `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

  - **`name` (required)**

    `string`

  - **`score` (required)**

    `number` — Match similarity in \[0, 1]. 1 = exact, lower = fuzzier.

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa/areeiro",
      "name": "Areeiro",
      "breadcrumb": "Areeiro, Lisboa, Portugal",
      "kind": null,
      "country": null,
      "centroid": null,
      "score": 0.83
    }
  ]
}
```

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

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

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code.

  - **`message` (required)**

    `string` — Human-readable explanation.

  - **`request_id` (required)**

    `string` — Echo of the \`x-request-id\` header for log correlation.

  - **`scope`**

    `string` — Limiter / auth scope that rejected the request, when applicable.

**Example:**

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

### Get a location by id

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

#### Responses

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

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

- **`centroid` (required)**

  `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

- **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

- **`depth` (required)**

  `integer` — Zero-based depth in the country's location tree (country = 0).

- **`id` (required)**

  `string`

- **`is_final` (required)**

  `boolean` — True when this location is a leaf in the crawl tree (no further administrative children).

- **`kind` (required)**

  `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

- **`name` (required)**

  `string`

- **`parent_id` (required)**

  `string | null`

- **`uri` (required)**

  `string`

**Example:**

```json
{
  "id": "pt/lisboa",
  "parent_id": "pt",
  "country": "PT",
  "name": "Lisboa",
  "kind": "town",
  "uri": "lisboa",
  "is_final": false,
  "depth": 1,
  "centroid": [
    -9.1393,
    38.7223
  ]
}
```

##### Status: 404 No location matches the supplied id.

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

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code.

  - **`message` (required)**

    `string` — Human-readable explanation.

  - **`request_id` (required)**

    `string` — Echo of the \`x-request-id\` header for log correlation.

  - **`scope`**

    `string` — Limiter / auth scope that rejected the request, when applicable.

**Example:**

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

### Get a place's boundary polygon

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

#### Responses

##### Status: 200 A GeoJSON-like boundary.

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

- **`bbox` (required)**

  `array` — \[minLon, minLat, maxLon, maxLat]

- **`geometry` (required)**

  `object`

  - **`type` (required)**

    `string`, possible values: `"Polygon", "MultiPolygon"`

  - **`coordinates`**

    `object`

- **`id` (required)**

  `string`

**Example:**

```json
{
  "id": "pt/lisboa",
  "geometry": {
    "type": "Polygon",
    "coordinates": null
  },
  "bbox": []
}
```

##### Status: 501 Route is declared but not yet implemented.

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

- **`error` (required)**

  `string` — Machine-readable error code.

- **`endpoint`**

  `string` — Route that produced the error.

- **`message`**

  `string` — Human-readable explanation.

**Example:**

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": ""
}
```

### Search addresses

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

Free-text address search scoped by country.

#### Responses

##### Status: 200 A page of address matches.

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

- **`data` (required)**

  `array`

  **Items:**

  - **`coord` (required)**

    `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`id` (required)**

    `string`

  - **`number` (required)**

    `string | null`

  - **`postcode` (required)**

    `string | null`

  - **`street` (required)**

    `string`

- **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`nextCursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa/rua-do-ouro/12",
      "country": null,
      "street": "Rua do Ouro",
      "number": "12",
      "postcode": "1100-062",
      "coord": null
    }
  ],
  "meta": {
    "limit": 1,
    "nextCursor": null
  }
}
```

##### Status: 501 Route is declared but not yet implemented.

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

- **`error` (required)**

  `string` — Machine-readable error code.

- **`endpoint`**

  `string` — Route that produced the error.

- **`message`**

  `string` — Human-readable explanation.

**Example:**

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": ""
}
```

### Look up a postal code

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

#### Responses

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

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

- **`centroid` (required)**

  `object`

- **`code` (required)**

  `string`

- **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

- **`placeId` (required)**

  `string | null`

**Example:**

```json
{
  "code": "1100-062",
  "country": "PT",
  "placeId": "pt/lisboa",
  "centroid": null
}
```

##### Status: 501 Route is declared but not yet implemented.

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

- **`error` (required)**

  `string` — Machine-readable error code.

- **`endpoint`**

  `string` — Route that produced the error.

- **`message`**

  `string` — Human-readable explanation.

**Example:**

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": ""
}
```

### Free-text geocoding

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

Resolve a free-text query into zero or more geographic matches.

#### Responses

##### Status: 200 A ranked list of matches.

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

- **`matches` (required)**

  `array`

  **Items:**

  - **`confidence` (required)**

    `number`

  - **`coord` (required)**

    `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`label` (required)**

    `string`

  - **`placeId` (required)**

    `string | null`

- **`query` (required)**

  `string`

**Example:**

```json
{
  "query": "",
  "matches": [
    {
      "label": "Rua do Ouro 12, 1100-062 Lisboa, PT",
      "country": null,
      "coord": null,
      "confidence": 0.84,
      "placeId": null
    }
  ]
}
```

##### Status: 501 Route is declared but not yet implemented.

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

- **`error` (required)**

  `string` — Machine-readable error code.

- **`endpoint`**

  `string` — Route that produced the error.

- **`message`**

  `string` — Human-readable explanation.

**Example:**

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": ""
}
```

## Schemas

### HealthResponse

- **Type:**`object`

* **`environment` (required)**

  `string`

* **`status` (required)**

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

* **`uptimeMs` (required)**

  `integer`

* **`version` (required)**

  `string`

**Example:**

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

### LocationListResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`centroid` (required)**

    `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`depth` (required)**

    `integer` — Zero-based depth in the country's location tree (country = 0).

  - **`id` (required)**

    `string`

  - **`is_final` (required)**

    `boolean` — True when this location is a leaf in the crawl tree (no further administrative children).

  - **`kind` (required)**

    `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

  - **`name` (required)**

    `string`

  - **`parent_id` (required)**

    `string | null`

  - **`uri` (required)**

    `string`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`nextCursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa",
      "parent_id": "pt",
      "country": null,
      "name": "Lisboa",
      "kind": null,
      "uri": "lisboa",
      "is_final": false,
      "depth": 1,
      "centroid": null
    }
  ],
  "meta": {
    "limit": 1,
    "nextCursor": null
  }
}
```

### Location

- **Type:**`object`

* **`centroid` (required)**

  `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

* **`depth` (required)**

  `integer` — Zero-based depth in the country's location tree (country = 0).

* **`id` (required)**

  `string`

* **`is_final` (required)**

  `boolean` — True when this location is a leaf in the crawl tree (no further administrative children).

* **`kind` (required)**

  `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

* **`name` (required)**

  `string`

* **`parent_id` (required)**

  `string | null`

* **`uri` (required)**

  `string`

**Example:**

```json
{
  "id": "pt/lisboa",
  "parent_id": "pt",
  "country": "PT",
  "name": "Lisboa",
  "kind": "town",
  "uri": "lisboa",
  "is_final": false,
  "depth": 1,
  "centroid": [
    -9.1393,
    38.7223
  ]
}
```

### CountryCode

- **Type:**`string`

ISO 3166-1 alpha-2 country code supported by Mapbase.

**Example:**

### LocationKind

- **Type:**`string`

**Example:**

### LonLat

- **Type:**`[ "array", "null" ]`

Representative \[lon, lat] point. Null when no geometry has been crawled yet.

**Example:**

### PageMeta

- **Type:**`object`

* **`limit` (required)**

  `integer`

* **`nextCursor` (required)**

  `string | null`

**Example:**

```json
{
  "limit": 1,
  "nextCursor": null
}
```

### LocationAutocompleteResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`breadcrumb` (required)**

    `string` — Hierarchical label leaf -> root, comma-separated.

  - **`centroid` (required)**

    `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`id` (required)**

    `string`

  - **`kind` (required)**

    `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

  - **`name` (required)**

    `string`

  - **`score` (required)**

    `number` — Match similarity in \[0, 1]. 1 = exact, lower = fuzzier.

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa/areeiro",
      "name": "Areeiro",
      "breadcrumb": "Areeiro, Lisboa, Portugal",
      "kind": null,
      "country": null,
      "centroid": null,
      "score": 0.83
    }
  ]
}
```

### LocationSuggestion

- **Type:**`object`

* **`breadcrumb` (required)**

  `string` — Hierarchical label leaf -> root, comma-separated.

* **`centroid` (required)**

  `array | null` — Representative \[lon, lat] point. Null when no geometry has been crawled yet.

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

* **`id` (required)**

  `string`

* **`kind` (required)**

  `string`, possible values: `"country", "province", "town", "district", "neighborhood"`

* **`name` (required)**

  `string`

* **`score` (required)**

  `number` — Match similarity in \[0, 1]. 1 = exact, lower = fuzzier.

**Example:**

```json
{
  "id": "pt/lisboa/areeiro",
  "name": "Areeiro",
  "breadcrumb": "Areeiro, Lisboa, Portugal",
  "kind": "town",
  "country": "PT",
  "centroid": [
    -9.1393,
    38.7223
  ],
  "score": 0.83
}
```

### ApiErrorEnvelope

- **Type:**`object`

* **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code.

  - **`message` (required)**

    `string` — Human-readable explanation.

  - **`request_id` (required)**

    `string` — Echo of the \`x-request-id\` header for log correlation.

  - **`scope`**

    `string` — Limiter / auth scope that rejected the request, when applicable.

**Example:**

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

### Boundary

- **Type:**`object`

* **`bbox` (required)**

  `array` — \[minLon, minLat, maxLon, maxLat]

* **`geometry` (required)**

  `object`

  - **`type` (required)**

    `string`, possible values: `"Polygon", "MultiPolygon"`

  - **`coordinates`**

    `object`

* **`id` (required)**

  `string`

**Example:**

```json
{
  "id": "pt/lisboa",
  "geometry": {
    "type": "Polygon",
    "coordinates": null
  },
  "bbox": []
}
```

### BoundaryGeometry

- **Type:**`object`

* **`type` (required)**

  `string`, possible values: `"Polygon", "MultiPolygon"`

* **`coordinates`**

  `object`

**Example:**

```json
{
  "type": "Polygon",
  "coordinates": null
}
```

### ErrorEnvelope

- **Type:**`object`

* **`error` (required)**

  `string` — Machine-readable error code.

* **`endpoint`**

  `string` — Route that produced the error.

* **`message`**

  `string` — Human-readable explanation.

**Example:**

```json
{
  "error": "not_implemented",
  "endpoint": "GET /v1/locations",
  "message": ""
}
```

### AddressSearchResponse

- **Type:**`object`

* **`data` (required)**

  `array`

  **Items:**

  - **`coord` (required)**

    `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`id` (required)**

    `string`

  - **`number` (required)**

    `string | null`

  - **`postcode` (required)**

    `string | null`

  - **`street` (required)**

    `string`

* **`meta` (required)**

  `object`

  - **`limit` (required)**

    `integer`

  - **`nextCursor` (required)**

    `string | null`

**Example:**

```json
{
  "data": [
    {
      "id": "pt/lisboa/rua-do-ouro/12",
      "country": null,
      "street": "Rua do Ouro",
      "number": "12",
      "postcode": "1100-062",
      "coord": null
    }
  ],
  "meta": {
    "limit": 1,
    "nextCursor": null
  }
}
```

### Address

- **Type:**`object`

* **`coord` (required)**

  `object`

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

* **`id` (required)**

  `string`

* **`number` (required)**

  `string | null`

* **`postcode` (required)**

  `string | null`

* **`street` (required)**

  `string`

**Example:**

```json
{
  "id": "pt/lisboa/rua-do-ouro/12",
  "country": "PT",
  "street": "Rua do Ouro",
  "number": "12",
  "postcode": "1100-062",
  "coord": null
}
```

### Postcode

- **Type:**`object`

* **`centroid` (required)**

  `object`

* **`code` (required)**

  `string`

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

* **`placeId` (required)**

  `string | null`

**Example:**

```json
{
  "code": "1100-062",
  "country": "PT",
  "placeId": "pt/lisboa",
  "centroid": null
}
```

### GeocodeResponse

- **Type:**`object`

* **`matches` (required)**

  `array`

  **Items:**

  - **`confidence` (required)**

    `number`

  - **`coord` (required)**

    `object`

  - **`country` (required)**

    `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

  - **`label` (required)**

    `string`

  - **`placeId` (required)**

    `string | null`

* **`query` (required)**

  `string`

**Example:**

```json
{
  "query": "",
  "matches": [
    {
      "label": "Rua do Ouro 12, 1100-062 Lisboa, PT",
      "country": null,
      "coord": null,
      "confidence": 0.84,
      "placeId": null
    }
  ]
}
```

### GeocodeMatch

- **Type:**`object`

* **`confidence` (required)**

  `number`

* **`coord` (required)**

  `object`

* **`country` (required)**

  `string`, possible values: `"PT", "ES", "IT"` — ISO 3166-1 alpha-2 country code supported by Mapbase.

* **`label` (required)**

  `string`

* **`placeId` (required)**

  `string | null`

**Example:**

```json
{
  "label": "Rua do Ouro 12, 1100-062 Lisboa, PT",
  "country": "PT",
  "coord": null,
  "confidence": 0.84,
  "placeId": null
}
```
